The credential failed OR pg_hba.conf demanded a method the connection didn't use. Peer auth is the trap: local TCP with password is fine, but a socket connection as a different OS user fails no matter the password.
Apps often default to the OS username as the PG user and to a db matching it: psql -U is not optional for non-matching names. Reset cleanly: ALTER USER x WITH PASSWORD 'y'; and test the exact DSN the app uses.
The host-based rules pick the auth method per connection origin. peer demands you BE the OS user; scram demands the password. An app connecting via socket as root fails peer regardless of password correctness. The error message is identical.
psql "host=<h> port=<p> user=<u> dbname=<db>" -W # same host = same pg_hba rule
sudo -u postgres psql -c "ALTER USER <user> WITH PASSWORD '<newpass>';"
sudo grep -v '^#' /etc/postgresql/*/main/pg_hba.conf | head -10
# host all all <app-cidr> scram-sha-256 then: systemctl reload postgresql (reload, not restart)
scram-sha-256 (default since PG14) rejects md5-hashed stored passwords: old pg_hba entries + new server = auth failures that 'should work'. Reset the password after changing methods. The server log names the actual rule used: authentication failed line includes host, user, and the hba entry. Faster than guessing which of ten rules matched.
peer auth: as the postgres OS user over the socket, no password is needed. The app connects over TCP as a different identity — different pg_hba line, different rules. That asymmetry is by design.
The newer, salted challenge method. Servers defaulting to it reject passwords stored as md5 hashes: set the password again AFTER enabling scram, and keep clients' drivers current.
Our most-documented failures, packaged as ready-to-ship starter kits: Docker, Kubernetes, and Terraform.
Browse the template store →One-time. Yours to modify. Instant download from the NinjaOps template store.