Another nice feature just made it into PostgreSQL 15: You can now control who is allowed to set specific parameters. This gives you a lot more flexibility, especially when you are hosting PostgreSQL instances for your customers. You can delegate more control to trusted users or roles and of course, you can also revoke it later on when it is not anymore required. One goal of this is to reduce the number of tasks which require superuser privileges. As always, lets do a simple example to highlight how you might use it.
To start with, we create a new user and connect with it:
postgres=# create user u with login password 'u'; CREATE ROLE postgres=# c postgres u You are now connected to database "postgres" as user "u".
Which parameters is this user allowed to set? Nothing on the instance and database level:
postgres=> alter system set work_mem='12MB'; ERROR: permission denied to set parameter "work_mem" postgres=> alter database postgres set work_mem='12MB'; ERROR: must be owner of database postgres
Of course the user can set a new value for himself (either permanently or in the session):
postgres=> alter user u set work_mem='12MB'; ALTER ROLE postgres=> set work_mem='10MB'; SET
This works for all parameters that have a context of “user” in pg_settings:
postgres=> select name,context from pg_settings where context = 'user' order by 1;
name | context
-------------------------------------+---------
application_name | user
array_nulls | user
backend_flush_after | user
backslash_quote | user
bytea_output | user
check_function_bodies | user
client_connection_check_interval | user
client_encoding | user
client_min_messages | user
commit_siblings | user
constraint_exclusion | user
cpu_index_tuple_cost | user
cpu_operator_cost | user
cpu_tuple_cost | user
cursor_tuple_fraction | user
DateStyle | user
debug_pretty_print | user
debug_print_parse | user
...
vacuum_cost_limit | user
vacuum_cost_page_dirty | user
vacuum_cost_page_hit | user
vacuum_cost_page_miss | user
vacuum_failsafe_age | user
vacuum_freeze_min_age | user
vacuum_freeze_table_age | user
vacuum_multixact_failsafe_age | user
vacuum_multixact_freeze_min_age | user
vacuum_multixact_freeze_table_age | user
wal_sender_timeout | user
wal_skip_threshold | user
work_mem | user
xmlbinary | user
xmloption | user
(136 rows)
For all the other parameters it does not work:
postgres=> select name,context from pg_settings where context != 'user' order by 1;
name | context
----------------------------------------+-------------------
allow_in_place_tablespaces | superuser
allow_system_table_mods | superuser
archive_cleanup_command | sighup
archive_command | sighup
archive_library | sighup
archive_mode | postmaster
archive_timeout | sighup
authentication_timeout | sighup
...
wal_sync_method | sighup
wal_writer_delay | sighup
wal_writer_flush_after | sighup
zero_damaged_pages | superuser
(202 rows)
postgres=> set track_counts='on';
ERROR: permission denied to set parameter "track_counts"
postgres=>
These times are now over: From PostgreSQL 15 on you can grant setting specific parameters to users or roles:
postgres=# select current_user; current_user -------------- postgres (1 row) postgres=# grant set on parameter track_counts to u; GRANT postgres=# c postgres u You are now connected to database "postgres" as user "u". postgres=> set track_counts = 'on'; SET postgres=>
This also works on the instance level:
postgres=# grant alter system on parameter shared_buffers to u; GRANT postgres=# c postgres u You are now connected to database "postgres" as user "u". postgres=> alter system set shared_buffers = '129MB'; ALTER SYSTEM postgres=>
A new catalog view comes alongside which lists all the grants for parameters:
postgres=> c postgres
You are now connected to database "postgres" as user "u".
postgres=> select * from pg_parameter_acl;
oid | parname | paracl
-------+----------------+-------------------------------------
16392 | track_counts | {postgres=sA/postgres,u=s/postgres}
16393 | wal_level | {postgres=sA/postgres,u=s/postgres}
16394 | shared_buffers | {postgres=sA/postgres,u=A/postgres}
(3 rows)
Nice, thanks to all involved.