@keithf4, hi
I have faced with the wrong behavior running script as db's owner.
Description
When executing the bloat analysis script with a database user that owns objects but lacks superuser privileges, the script fails with a permission error when attempting to analyze TOAST tables.
Traceback (most recent call last): File "/Users/andrey.samsonov/utils/pg_bloat_check/./pg_bloat_check.py", line 700, in <module> get_bloat(conn, tuple(exclude_schema_list), tuple(include_schema_list), exclude_object_list) ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/andrey.samsonov/utils/pg_bloat_check/./pg_bloat_check.py", line 332, in get_bloat cur.execute(sql) ~~~~~~~~~~~^^^^^ File "/Users/andrey.samsonov/myenv/lib/python3.14/site-packages/psycopg2/extras.py", line 146, in execute return super().execute(query, vars) ~~~~~~~~~~~~~~~^^^^^^^^^^^^^ psycopg2.errors.InsufficientPrivilege: permission denied for schema pg_toast
This occurs because the pg_toast schema requires elevated privileges that are typically not granted to regular database owners in cloud environments and properly secured database instances.
Root Cause
The script assumes the connecting user has privileges to access all system schemas, including pg_toast. However, cloud PostgreSQL providers typically separate superuser and administrative privileges for security reasons. Keeping that in mind pg_toast schema requires special privileges that are not available to regular database owners
Impact
Bloat analysis cannot be completed for any user without superuser privileges
Possible solution
Exclude pg_toast schema from analyzing. Separate TOAST analysis provides minimal additional value as bloat percentage in toast is similar to tables which they are associated with.
if exists == 0: continue # just skip over it. object was dropped since initial list was made if o['nspname'] == "pg_toast": continue if args.noanalyze != True: if o['relkind'] == "r" or o['relkind'] == "m" or o['relkind'] == "t": quoted_table = "\"" + o['nspname'] + "\".\"" + o['relname'] + "\""
Waiting for your response.
@keithf4, hi
I have faced with the wrong behavior running script as db's owner.
Description
When executing the bloat analysis script with a database user that owns objects but lacks superuser privileges, the script fails with a permission error when attempting to analyze TOAST tables.
Traceback (most recent call last): File "/Users/andrey.samsonov/utils/pg_bloat_check/./pg_bloat_check.py", line 700, in <module> get_bloat(conn, tuple(exclude_schema_list), tuple(include_schema_list), exclude_object_list) ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/andrey.samsonov/utils/pg_bloat_check/./pg_bloat_check.py", line 332, in get_bloat cur.execute(sql) ~~~~~~~~~~~^^^^^ File "/Users/andrey.samsonov/myenv/lib/python3.14/site-packages/psycopg2/extras.py", line 146, in execute return super().execute(query, vars) ~~~~~~~~~~~~~~~^^^^^^^^^^^^^ psycopg2.errors.InsufficientPrivilege: permission denied for schema pg_toastThis occurs because the pg_toast schema requires elevated privileges that are typically not granted to regular database owners in cloud environments and properly secured database instances.
Root Cause
The script assumes the connecting user has privileges to access all system schemas, including pg_toast. However, cloud PostgreSQL providers typically separate superuser and administrative privileges for security reasons. Keeping that in mind pg_toast schema requires special privileges that are not available to regular database owners
Impact
Bloat analysis cannot be completed for any user without superuser privileges
Possible solution
Exclude pg_toast schema from analyzing. Separate TOAST analysis provides minimal additional value as bloat percentage in toast is similar to tables which they are associated with.
if exists == 0: continue # just skip over it. object was dropped since initial list was made if o['nspname'] == "pg_toast": continue if args.noanalyze != True: if o['relkind'] == "r" or o['relkind'] == "m" or o['relkind'] == "t": quoted_table = "\"" + o['nspname'] + "\".\"" + o['relname'] + "\""Waiting for your response.