28000 — invalid_authorization_specification
28000
At a glance
SQLSTATE 28000 is invalid_authorization_specification in Class 28. 28000 is the authorization-specification class for rejected startup or authorization context. The selected missing-role startup path sends C=28000, S=FATAL, and role "<generated>" does not exist before a session is established; other fixed authentication paths use this class for concrete certificate, pg_hba, and LOGIN eligibility failures.
| Field | Value |
|---|---|
| SQLSTATE | 28000 |
| Condition | invalid_authorization_specification |
| Status | active |
| Known present by | 7.4 |
| Locked snapshots | 9.0.23, 9.1.24, 9.2.24, 9.3.25, 9.4.26, 9.5.25, 9.6.24, 10.23, 11.22, 12.22, 13.23, 14.24, 15.19, 16.15, 17.11, 18.6, 19beta3 |
| Macros | ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION |
| Aliases | — |
Meaning
This class covers authorization context rejected while a connection is being established or authenticated. The selected branch is the startup role lookup: the server cannot create a session for the requested role and sends a FATAL ErrorResponse. Certificate, pg_hba, and LOGIN-eligibility paths remain separate producers under the same class.
The selected role lookup happens before a backend can enter a normal session. That explains both the FATAL severity and the absence of session-level transaction state. Do not merge it with 28P01 (password authentication failure), 42501 (permission denied after a session exists), or 3D000 (database selection); the startup phase and the server fields identify which branch you are looking at.
Startup branch guide
| What to inspect | Selected missing-role branch | Other Class 28 possibilities |
|---|---|---|
| Server field | C=28000, S=FATAL, M=role "%s" does not exist |
Preserve the server’s own code and primary; class membership alone is not enough. |
| Session state | No usable session and no transaction exists on the failed attempt | A later authorization check may occur after a session exists and has a different recovery boundary. |
| Repair | Create/rename the role as intended, or correct the startup user, then connect afresh | Correct the certificate, pg_hba.conf, LOGIN attribute, or mapping named by the actual diagnostic. |
Diagnosis
Use the server ErrorResponse or authentication log as SQLSTATE authority and classify the phase: role lookup, pg_hba rule, certificate, or LOGIN permission. The selected collector is a raw server ErrorResponse record, not csvlog/jsonlog; raw startup and psycopg are separate attempts. In the selected runs psycopg reports driver SQLSTATE null, the failed connection has no transaction, and two independent fresh known-role probes can still run SELECT 1; this is not a collector correlation claim.
For a missing role, compare the requested startup user with the role catalog from a separate administrative session and check for quoting or case-folding differences. Preserve the raw C, S, and M fields: psycopg’s null is a property of its independent failed startup attempt, not evidence that the server omitted SQLSTATE. A fresh probe must use a separate connection and cannot turn the failed attempt into a transaction that can be rolled back.
Response
Correct the role, LOGIN/mapping, certificate, or pg_hba rule identified by the server, then establish a fresh connection. There is no failed session on which to issue ROLLBACK; do not infer 28000 from a client exception without its server field, and do not replay non-idempotent startup work blindly.
After a role or authentication change, reconnect with the exact intended user and database and verify the resulting identity from the new session. If the application had already sent work on another connection, reconcile that work separately; the pre-session FATAL itself does not establish a business transaction to retry.
Observed diagnostics
The selected startup role branch emits FATAL with primary role "%s" does not exist; the role name is dynamic. Other authorization failures in Class 28 can use different primary text. Treat the server ErrorResponse as authoritative because the client never receives a usable session SQLSTATE.
The selected server record is role "u28000_missing_fbc912bb7e6f" does not exist; the generated role name is run-specific. The raw ErrorResponse and the psycopg null belong to separate startup attempts, so they must not be combined as if they were two views of one session.
Representative case
The registry contains the probe used after the startup ErrorResponse. The trigger uses a generated role on a fresh startup connection, so no SQL statement can reproduce that pre-session failure.
The selected 18.6 server ErrorResponse is C=28000, S=FATAL, role "u28000_missing_fbc912bb7e6f" does not exist. The driver startup diagnostic has SQLSTATE null; the failed connection has no transaction, while the known-good probe returned 1 and IDLE.
The downloadable case and evidence projections are 28000 case JSON and authored evidence. The runner manifest is verify/cases/28000/cases.json; the page SQL is checked against its shared registry before publication.
Versions
The generated facts table records the locked catalogue snapshots and earliest observed definition. The selected natural runtime scope is PostgreSQL 18.6 and 10.21; this does not infer behavior for every intermediate release.
Related
Sources
src.miscinit-missing-role.18.6—src/backend/utils/init/miscinit.catREL_18_6commit724edf9bde9d356724ad384a2e196edc3c9f80f7; fixed blob SHA-25654bdb859c143a6c70d86067ccf2e124f59aa0852e5705bb653652e41a60af39a(source).src.miscinit-missing-role.10.23—src/backend/utils/init/miscinit.catREL_10_23commit02991e79f8f58bc208f05dcc8af0c62dbe0a6ea4; fixed blob SHA-256c4d2e234f96644d43aad9e9a6728df693e7f75175f05a550701413ceee70fb82(source).src.calls.REL_18_6/src.calls.REL_10_23— fixed local call scans, SHA-2569ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf/00d16d3eb01b71ccf1b245c8f3102f9d0ec9f36fb02777b8dd1b99fcb263040c; these scans preserve the resolved call context used by the claims.