select open change scope Open full search

PG.CENTER connects PostgreSQL documentation, reference, and ecosystem knowledge. Maintained by Pigsty.

SQLSTATE / CLASS 28 · INVALID AUTHORIZATION SPECIFICATION

invalid_password

SQLSTATE
28P01
Condition name
invalid_password
Class
Invalid Authorization Specification
Source macro
ERRCODE_INVALID_PASSWORD
Evidence
Observed at runtime in the source evidence
Analysis & operational context

English SQLSTATE atlas: authored explanations and source/runtime evidence are separate from the manual definitions. View source ↗

At a glance

28P01 is PostgreSQL's invalid_password condition in Class 28, invalid_authorization_specification. It identifies a password authentication failure while a client is establishing a session. The authentication method, the matched pg_hba.conf rule, and the role's stored secret determine the precise path.

This failure occurs before SQL execution. The rejected session has no transaction to roll back. In the final runs, psycopg reported the startup exception text but exposed sqlstate=None; the PostgreSQL collector recorded the server's FATAL SQLSTATE 28P01. A driver-side exception without a code must not be described as if the client received the collector field.

The case wrong_password_authentication enabled a disposable md5 rule, tried a wrong password, verified that the known password could open a new session and run SELECT 1, restored the exact HBA configuration, and verified a fresh management connection. It passed on PostgreSQL 18.6 and isolated PostgreSQL 10.21. The run IDs and assertions are retained in the public evidence JSON.

Meaning and trigger paths

The server selects an authentication method from the first matching pg_hba.conf rule. For password, MD5, and SCRAM paths that reject the supplied secret, auth.c selects ERRCODE_INVALID_PASSWORD and reports a FATAL message. The primary template is password authentication failed for user "%s"; the server can add HBA matching information to its log detail.

28P01 does not distinguish a wrong password from every other authentication configuration problem. A missing role, a role that cannot log in, a certificate failure, or an HBA rule that selects another method can use a different SQLSTATE or message. The matched rule and the authentication method are part of the diagnosis.

The failure is at connection startup, before a backend can accept SQL. A pool should discard the rejected connection attempt and obtain a new one after the secret or HBA configuration is repaired. Existing owner or administration connections are useful for restoring a temporary rule, but reusing one of them does not prove that the affected role can authenticate.

Messages and diagnostics

The SQL statements below are the same password setup and probe statements used by the runner. known_user and example-known-secret are replaced by disposable values during the run. Editing pg_hba.conf and opening the wrong-password connection are startup operations, so they are described between the SQL statements rather than represented by a fake RAISE or SQL error.

ALTER ROLE known_user PASSWORD 'example-known-secret';
-- Put a temporary first pg_hba.conf rule for host all all 0.0.0.0/0 md5.
-- Connect as known_user with a wrong password: startup returns FATAL 28P01.
-- Connect again with the known password and run:
SELECT 1;
-- Restore the original pg_hba.conf, open a fresh management connection, and run:
SELECT 1;

The latest target's collector record was:

SQLSTATE: 28P01
severity: FATAL
message_primary: password authentication failed for user "<generated-role>"
detail (collector): Connection matched file "<pg_hba.conf path>" line 1: "host all all 0.0.0.0/0 md5"
source: auth.c / auth_failed / line 320
driver startup sqlstate: null
transaction: none opened
repair: known-password SELECT 1 -> 1; restore HBA; fresh owner SELECT 1 -> 1

PostgreSQL 10.21 emitted the same primary message and SQLSTATE in its collector, with auth.c:329 as the source location; its collector detail uses the older pg_hba.conf line wording and also includes a password-mismatch line. In both targets the known password authenticated under the temporary rule, the original HBA configuration was reloaded, and a new management connection then returned 1. The driver text and collector fields are separate evidence channels; libpq/psycopg did not expose the startup SQLSTATE in this run.

Diagnosis

Record the user, database, connection source, authentication method, server version, and the first matching HBA rule without recording passwords. Correlate the failed attempt with a verbose collector record. The collector detail can identify the HBA line, while the client startup exception may contain only a FATAL text string.

Check that the intended role exists and can log in, that its password was set for the selected method, and that no earlier HBA rule intercepts the connection. A correct password under the wrong HBA method is not proof of a correct deployment. Avoid treating a password rotation as complete until a new connection succeeds.

There is no transaction state to recover for the rejected session. Keep a controlled administration connection while changing HBA rules, reload the configuration, and test with a fresh client. Restore the prior rule exactly when the test is complete and verify that a new owner connection still works.

Response and repair

  • Use the intended secret and authentication method for the role, and rotate it through a channel that does not expose the value in logs or command history.
  • Inspect the first matching pg_hba.conf rule, correct its database, user, address, and method fields, then reload it.
  • Test the affected role with a new connection and a real harmless query such as SELECT 1.
  • Keep existing administration access until the new path is proven, then close stale pool connections so they do not retain old credentials.

The representative repair includes both a known-password connection and a fresh post-restore management connection. A successful pg_reload_conf() alone is not an authentication proof, and reusing the connection that performed the reload does not test the repaired login path.

Versions and boundaries

The catalogue contains 28P01 in the first scanned definition (9.0.0 or earlier), every listed formal snapshot through PostgreSQL 18.6, and the PostgreSQL 19 Beta 3 preview. No condition definition change is recorded in the scanned range; the pre-9.0 introduction point remains outside the scan.

The wrong-password case passed on PostgreSQL 18.6 and 10.21. The source line differs between releases, and the driver/collector SQLSTATE split is a property of this startup path. Certificate, GSSAPI, PAM, LDAP, peer, and HBA syntax failures are separate authentication paths and are not covered by this evidence.

Sources

Structured evidence is recorded in the public evidence JSON. Source records are fixed to PostgreSQL commit 724edf9bde9d356724ad384a2e196edc3c9f80f7; runtime records retain the collector output, driver observation, HBA restoration, both target IDs, and structured observations.

Source evidence

Evidence belongs to the frozen source and runtime versions listed here. It is not a runtime verification of the selected manual version.

28P01 is the invalid_password condition in Class 28 invalid_authorization_specification.

Method: Read the Class 28 section and 28P01 row in the frozen errcodes.txt snapshot.

Limits: Directory identity does not identify the selected authentication method or the matched HBA rule.

src.errcodes.18.6

The password authentication failure path in auth.c selects ERRCODE_INVALID_PASSWORD, reports password authentication failed for user "%s" at FATAL, and may add the matched pg_hba.conf line to log detail.

Method: Trace auth_failed's password/MD5/SCRAM error selection and detail construction and compare the official HBA and password-authentication rules.

Limits: Other authentication methods and HBA configuration errors use separate branches and can report different SQLSTATEs or messages.

src.auth.18.6 doc.client-auth.18

For the rejected startup connection, psycopg exposed startup text with sqlstate null while the PostgreSQL collector recorded FATAL SQLSTATE 28P01 and the password-failure message on both targets.

Method: Compare driver diagnostics and collector SQL state code, severity, message, HBA detail, and source location in both final summaries and raw records.

Limits: Driver exposure can vary by client and startup failure; the collector record is the server-side SQLSTATE evidence here.

doc.protocol.18 runtime.28P01-registry-final-20260909.latest runtime.28P01-registry-final-20260909.pg10

After enabling the temporary md5 rule, the known password opened a new role connection and returned SELECT 1 = 1; after exact HBA restoration, a fresh management connection also returned 1 on both targets.

Method: Use an owner connection to set the disposable role password, reload the temporary HBA rule, test wrong and known passwords through new connections, restore and reload the original rule, and assert a fresh owner probe.

Limits: The run proves a password failure under the controlled md5 rule; it does not cover certificate, GSSAPI, PAM, LDAP, peer, or HBA syntax failures.

case-manifest.28P01 snippet-registry.28P01.final runtime.28P01-registry-final-20260909.latest runtime.28P01-registry-final-20260909.pg10

The locked catalogue records 28P01 in every listed formal snapshot from 9.0.23 through 18.6 and in 19beta3; pre-9.0 history is not scanned.

Method: Read the manifest snapshots and definition references for the code.

Limits: The first scanned release is a lower bound, not an asserted introduction version.

manifest.28P01

Message templates

explicit FATAL · message.password-failure

Primary

password authentication failed for user "%s"

Detail

Connection matched file "%s" line %d: "%s"

The fixed PG18.6 source passes logdetail through errdetail_log; a client ErrorResponse need not expose it. PG10 collector output uses a release-specific pg_hba.conf wording and may include an additional password-mismatch line.

Reproduction & repair cases

wrong_password_authentication · PG 10, 18

Preconditions

  • A disposable login role with a known password
  • A temporary first pg_hba.conf rule uses md5 and is reloaded

Trigger: Connect with a wrong password and retain the server's authentication diagnostic.

Expected assertions

  • The connection attempt receives SQLSTATE 28P01
  • The server does not open a transaction for the rejected connection
  • The known password opens a new session while the temporary rule is active
  • A fresh management connection succeeds after the original configuration is restored

Repair: Use the intended secret and authentication method, verify a new connection, then restore or rotate credentials without logging passwords.

Cleanup: Restore pg_hba.conf and drop the role and schema.

Recorded runtime evidence

18.6 (Homebrew) · passed

Run: 28P01-registry-final-20260909

{
  "hba_reload": {
    "enabled": true,
    "restored": true
  },
  "driver_text": "FATAL: password authentication failed for user <generated-role>",
  "transaction": "none opened for rejected startup",
  "driver_sqlstate": null,
  "collector_detail": "Connection matched file \"<pg_hba.conf path>\" line 1: \"host all all 0.0.0.0/0 md5\"",
  "collector_source": "auth.c:320",
  "collector_message": "password authentication failed for user <generated-role>",
  "collector_severity": "FATAL",
  "collector_sqlstate": "28P01",
  "known_password_probe": 1,
  "restored_management_probe": 1
}
10.21 (Debian 10.21-1.pgdg90+1) · passed

Run: 28P01-registry-final-20260909

{
  "hba_reload": {
    "enabled": true,
    "restored": true
  },
  "driver_text": "FATAL: password authentication failed for user <generated-role>",
  "transaction": "none opened for rejected startup",
  "driver_sqlstate": null,
  "collector_detail": "Password does not match for user <generated-role>.\\nConnection matched pg_hba.conf line 1: \"host all all 0.0.0.0/0 md5\"",
  "collector_source": "auth.c:329",
  "collector_message": "password authentication failed for user <generated-role>",
  "collector_severity": "FATAL",
  "collector_sqlstate": "28P01",
  "known_password_probe": 1,
  "restored_management_probe": 1
}

Definition snapshot: english-manuals:9114f4935d23d3c8fd4d9a151c9… · English manual source