Skip to main content
RunBook Academy

PostgreSQLV · Authentication, Roles and TLSAuthorisation

Superuser, and what it really grants

Advanced⏱ ~25 minpsql

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

Not yet marked complete on this device.

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.

CapabilityReaches
COPY ... FROM PROGRAM / TO PROGRAMExecutes 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 functionsReads arbitrary files
CREATE EXTENSION of an untrusted extensionLoads native code into the server process
CREATE LANGUAGE for an untrusted languageRuns arbitrary code in the backend
ALTER SYSTEMChanges 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.

Read-only / Safethe predefined roles that are effectively host access
$ 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
GrantWhy it is superuser-equivalent
pg_execute_server_programRuns shell commands as the database OS user
pg_write_server_filesWrites any file that user can, including its own authorised keys
pg_read_server_filesReads any file that user can, including the data files
CREATEROLEHistorically could grant itself membership of other roles; restricted in 16 and still powerful
Ownership of a function called by a superuserThe function runs with the caller’s privileges unless SECURITY DEFINER says otherwise
Membership of a role that owns everythingCan 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:

  1. Inventory. Every superuser, every superuser-equivalent membership, every role with CREATEROLE or BYPASSRLS.
  2. For each, establish what it actually does. pg_stat_statements and the audit trail answer this better than asking.
  3. Grant the narrow roles alongside the existing superuser. Privileges are additive, so nothing breaks at this stage.
  4. Remove the superuser attribute, one role at a time, with a rollback ready.
  5. 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

  1. Treat a superuser grant as a host access decision, and route it through whoever approves host access.
  2. Never give an application superuser. Its credential appears in configuration, images, CI logs and error reports.
  3. Audit for superuser-equivalent grants, not just rolsuper. The three server-file and program roles confer the same reach.
  4. Replace with the narrowest predefined role. pg_monitor, pg_maintain, pg_signal_backend and pg_checkpoint cover most historical reasons for the grant.
  5. Reduce additively. Grant the narrow roles first, remove superuser second, verify by reconnecting.
  6. Keep exactly two superusers deliberately: a vaulted break-glass account with alerting on its use, and local peer administration.
  7. 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

  1. Q1. Why should a PostgreSQL superuser grant be reviewed by whoever approves host access?

  2. Q2. A maintenance job needs to VACUUM and ANALYZE tables it does not own. What is the correct grant?

  3. Q3. Which grants are effectively equivalent to superuser in reach? Select all that apply.

  4. Q4. ALTER ROLE x NOSUPERUSER immediately removes superuser privileges from that role's existing sessions.

  5. Q5. Give the safe order for removing superuser from an existing role, and say why that order matters.

  6. 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.