User Guide
Executor privileges
pgroles does not require superuser. It needs CREATEROLE plus a handful of scoped grants, and the exact set depends on whether the roles you manage are new or already exist.
What pgroles actually needs
This table was verified against a live PostgreSQL 16 server. CREATEROLE is the load-bearing attribute; everything else is either automatic (for roles the executor created itself) or a narrow, explicit grant.
| pgroles operation | Requires |
|---|---|
CREATE ROLE | CREATEROLE attribute |
ALTER ROLE / COMMENT ON ROLE / passwords / ALTER ROLE ... SET config | CREATEROLE + ADMIN OPTION on the target role (automatic for roles the executor created itself) |
GRANT/REVOKE role memberships | ADMIN OPTION on the granted (group) role — automatic for roles the executor created |
DROP ROLE | CREATEROLE + ADMIN OPTION on the role |
CREATE SCHEMA | CREATE privilege on the database |
ALTER SCHEMA ... OWNER TO | ownership of the schema plus membership in the new owner role |
GRANT/REVOKE on tables/sequences/functions | ownership of the objects, directly or via membership in the owning role |
ALTER DEFAULT PRIVILEGES FOR ROLE x | membership (privileges) of role x — ADMIN OPTION alone is not enough |
REASSIGN OWNED BY a TO b (retirements) | membership (privileges) of both a and b. The executor has ADMIN OPTION on roles it created, so it can GRANT a TO executor itself first — pgroles does not do this automatically |
DROP OWNED BY a (retirements) | membership (privileges) of a |
terminate_sessions (retirements) | membership in pg_signal_backend (cannot terminate superuser sessions) |
inspection (diff/plan/generate) | none beyond CONNECT — pg_roles, pg_shdescription, and ACL columns are readable by any role |
Why greenfield is nearly free and brownfield has friction
PostgreSQL 16 changed CREATEROLE semantics: a role with CREATEROLE automatically receives ADMIN OPTION on any role it creates. That collapses most of the table above into a single attribute for a greenfield executor — one that creates every role it will later alter, grant, or drop. A fresh executor needs only:
CREATEROLECREATEon the target database (to create schemas)- membership in the schema-owner role(s) it manages default privileges for
The friction shows up in brownfield adoption. CREATEROLE does not retroactively grant ADMIN OPTION on roles that already existed before the executor was created. For every pre-existing role pgroles needs to alter, drop, or manage memberships on, a superuser or existing admin must explicitly grant the executor admin rights:
GRANT adopted_role TO executor WITH ADMIN TRUE;
Without this, pgroles can still create new roles and manage grants on objects the executor owns, but altering or dropping the adopted role, or changing its memberships, fails with a permission error. See the staged adoption guide for the broader brownfield rollout sequence.
Bootstrap SQL
Run once, by a superuser or an existing admin (RDS rds_superuser member, Cloud SQL cloudsqlsuperuser member, AlloyDB alloydbsuperuser member, etc.), before pointing pgroles at a database for the first time:
-- Run once as superuser / cloud admin user.
-- 1. The role pgroles connects as.
CREATE ROLE pgroles_executor WITH LOGIN PASSWORD '...' CREATEROLE;
-- 2. Let it create schemas in the target database.
GRANT CREATE ON DATABASE mydb TO pgroles_executor;
-- 3. If pgroles will manage default privileges owned by an existing
-- schema-owner role, give the executor membership in that role.
GRANT app_owner TO pgroles_executor;
-- 4. Brownfield only: for each pre-existing role pgroles must alter,
-- drop, or manage memberships on, grant explicit admin rights.
GRANT some_preexisting_role TO pgroles_executor WITH ADMIN TRUE;
Steps 1–2 cover a greenfield executor. Steps 3–4 are additive, per-role grants you add as you bring existing roles under pgroles management.
Cloud providers
None of RDS, Cloud SQL, AlloyDB, or Azure Database for PostgreSQL expose true superuser. The bootstrap above is run by the provider's admin user instead — rds_superuser member on RDS/Aurora, cloudsqlsuperuser member on Cloud SQL, alloydbsuperuser member on AlloyDB. See the AWS RDS & Aurora and Google Cloud SQL pages for the specific attributes those admin roles lack and how pgroles adapts around them.
For Cloud SQL IAM authentication, the operator can authenticate as a low-privilege IAM identity and SET ROLE to a privileged parent role on every connection via connection.params.setRole — see the operator connection docs for the full pattern.
The superuser shortcut
Running pgroles as superuser works and satisfies every row in the table above automatically — there is nothing to grant, adopt, or troubleshoot. The cost is the one every DBA already weighs: the connection can do anything to the cluster, not just what pgroles' manifest describes. Scoped CREATEROLE privileges are the recommended default; superuser is a pragmatic fallback for small or throwaway environments.