PostgreSQLV · Authentication, Roles and TLSAuthorisation
Superuser, and what it really grants
What you'll learn
- State what superuser bypasses and what it can reach beyond the database
- Identify the non-superuser grants that are superuser-equivalent
- Replace a superuser grant with the narrowest capability that satisfies the need
- Audit an estate for superuser and superuser-equivalent access
Prerequisites
Verified against PostgreSQL 18.x · PostgreSQL (comparison targets) 17.11, 16.15 · PostgreSQL (support calendar) 18, 17, 16, 15, 14 supported · pgBackRest 2.59.1 · PgBouncer 1.25.2 · Patroni 4.1.5 · Ubuntu (host baseline) 26.04 LTS · 2026-08-27
A superuser bypasses every permission check in the database. That much is expected. What is frequently not appreciated is that several superuser capabilities do not stop at the database boundary: they reach the filesystem and the host, as the operating-system account PostgreSQL runs as.
That makes a superuser grant a host access decision, and it should be reviewed by whoever reviews host access.
What it bypasses inside the database
Every privilege check. SELECT on any table in any database, DROP on
any object, ALTER on any role including changing its password.
Row-level security policies do not apply. GRANT and REVOKE need no
ownership.
Also every safety mechanism that is implemented as a privilege check,
which is a longer list than it sounds: the restrictions on
ALTER SYSTEM, on creating extensions, on reading the statistics of
other databases, and on terminating other sessions.
What it reaches outside the database
This is the part that changes the risk assessment.
| Capability | Reaches |
|---|---|
COPY ... FROM PROGRAM / TO PROGRAM | Executes shell commands as the database OS user |
COPY ... FROM '/path' / TO '/path' | Reads and writes any file that user can |
pg_read_server_files-equivalent functions | Reads arbitrary files |
CREATE EXTENSION of an untrusted extension | Loads native code into the server process |
CREATE LANGUAGE for an untrusted language | Runs arbitrary code in the backend |
ALTER SYSTEM | Changes what the server does at next restart |
COPY TO PROGRAM is the clearest case. A superuser can run a shell
command on the database host as the postgres account. From there,
reading the data directory, reading any credentials that account can
reach, and establishing persistence are ordinary operations.
Superuser-equivalent grants
An audit that counts rolsuper misses most of the exposure, because
several ordinary grants confer the same reach by a different route.
$ psql -U postgres -tAc "SELECT string_agg(rolname, ', ' ORDER BY rolname) FROM pg_roles WHERE rolname LIKE 'pg\_%server%' OR rolname = 'pg_execute_server_program'"pg_execute_server_program, pg_read_server_files, pg_write_server_files| Grant | Why it is superuser-equivalent |
|---|---|
pg_execute_server_program | Runs shell commands as the database OS user |
pg_write_server_files | Writes any file that user can, including its own authorised keys |
pg_read_server_files | Reads any file that user can, including the data files |
CREATEROLE | Historically could grant itself membership of other roles; restricted in 16 and still powerful |
| Ownership of a function called by a superuser | The function runs with the caller’s privileges unless SECURITY DEFINER says otherwise |
| Membership of a role that owns everything | Can drop or alter every object |
The audit query has to cover all of them:
# Superusers
psql -U postgres -c \
"SELECT rolname FROM pg_roles WHERE rolsuper ORDER BY 1"
# Superuser-equivalent memberships, resolved transitively
psql -U postgres -c \
"SELECT r.rolname AS role, g.rolname AS grants
FROM pg_auth_members m
JOIN pg_roles r ON r.oid = m.member
JOIN pg_roles g ON g.oid = m.roleid
WHERE g.rolname IN ('pg_execute_server_program',
'pg_read_server_files',
'pg_write_server_files')
ORDER BY 1"
# Roles with dangerous attributes
psql -U postgres -c \
"SELECT rolname, rolsuper, rolcreaterole, rolcreatedb, rolbypassrls
FROM pg_roles
WHERE rolsuper OR rolcreaterole OR rolbypassrls ORDER BY 1"
Reducing an existing estate
The order that avoids breaking things:
- Inventory. Every superuser, every superuser-equivalent
membership, every role with
CREATEROLEorBYPASSRLS. - For each, establish what it actually does.
pg_stat_statementsand the audit trail answer this better than asking. - Grant the narrow roles alongside the existing superuser. Privileges are additive, so nothing breaks at this stage.
- Remove the superuser attribute, one role at a time, with a rollback ready.
- Verify that the workload still functions before moving to the next.
ALTER ROLE x NOSUPERUSER takes effect for new sessions; existing
sessions keep the privileges they started with, so verification means
reconnecting rather than waiting.
Two roles genuinely need superuser and are worth keeping deliberately:
a break-glass account whose credential lives in a vault and whose use
is alerted on, and whatever the operating-system postgres account
uses for local maintenance via peer authentication.
Production discipline
- Treat a superuser grant as a host access decision, and route it through whoever approves host access.
- Never give an application superuser. Its credential appears in configuration, images, CI logs and error reports.
- Audit for superuser-equivalent grants, not just
rolsuper. The three server-file and program roles confer the same reach. - Replace with the narrowest predefined role.
pg_monitor,pg_maintain,pg_signal_backendandpg_checkpointcover most historical reasons for the grant. - Reduce additively. Grant the narrow roles first, remove superuser second, verify by reconnecting.
- Keep exactly two superusers deliberately: a vaulted break-glass
account with alerting on its use, and local
peeradministration. - Review installed extensions alongside superuser. A non-trusted extension is native code in the backend process.
Cross-course references
- Secrets, PKI & Certificate Management — Part I (Foundations) covers blast-radius calculation including transitive authority, which is exactly the reasoning that makes a superuser grant a host access decision, and Part XVIII covers responding to a compromised credential.
- Linux for Production Sysadmins — Part V (Sudo) covers the host equivalent, and Part XXXI (Audit) covers alerting on rare privileged actions.
- Kubernetes for Production Sysadmins — Part LVIII (RBAC) and Part LXIII (Linux security) cover the same escalation reasoning where a workload privilege becomes node access.
Quiz
Knowledge check · 6 questions
Q1. Why should a PostgreSQL superuser grant be reviewed by whoever approves host access?
Q2. A maintenance job needs to VACUUM and ANALYZE tables it does not own. What is the correct grant?
Q3. Which grants are effectively equivalent to superuser in reach? Select all that apply.
Q4. ALTER ROLE x NOSUPERUSER immediately removes superuser privileges from that role's existing sessions.
Q5. Give the safe order for removing superuser from an existing role, and say why that order matters.
Q6. Assess the exposure and give the reduction plan.
A security review of a production cluster finds four superusers: postgres, a break-glass account in a vault, a monitoring account whose credential is in a Prometheus exporter configuration on twelve hosts, and a backup account whose credential is in a systemd unit file on the database host. It also finds one non-superuser role, etl_runner, holding pg_execute_server_program, used by a nightly job that exports data to a file. The team considers only the first four to be in scope.
Passing score: 75%. Answers are checked in this browser.