ERROR 28P01: Password Authentication Failed in Postgres
Error Message
FATAL: password authentication failed for user "app_user"
SQLSTATE: 28P01You may also see a related log entry on the server:
DETAIL: User "app_user" has no password assigned.
Or when connecting via psql or a driver:
psql: error: connection to server at "localhost" (127.0.0.1), port 5432 failed:
FATAL: password authentication failed for user "app_user"
Description
PostgreSQL raises error 28P01 when a client provides a password that does not match the stored credential for the specified user, or when password authentication is required but no valid password is set. The full SQLSTATE code is 28P01 (invalid_password). This is the most common connection error for PostgreSQL and is almost always a configuration issue â not a bug in your application.
Causes
- Wrong password. The most obvious cause â the password supplied doesn't match what's stored for that role.
- Role has no password set. The role was created with
CREATE ROLE app_user LOGINbut without aPASSWORDclause, so any password attempt fails. - Wrong user. Connecting as
postgreswhen the application should connect asapp_user, or vice versa. - pg_hba.conf requires password auth but the role uses a different method. The
pg_hba.confentry saysmd5orscram-sha-256but the role's password was set with a different encryption method. - Password contains special characters. Characters like
@,#,%in the password may be misinterpreted by connection strings if not properly escaped or quoted. - Environment variable or config file has stale credentials. The password was rotated but
.pgpass,PGPASSWORD, or the application config still has the old one. - Connecting to the wrong server. The credentials are valid on staging but you're connecting to production (or vice versa).
- SCRAM vs MD5 mismatch. PostgreSQL 14+ defaults to
scram-sha-256. If the password was stored as MD5 andpg_hba.confrequires SCRAM, authentication fails.
Solutions
-
Reset the password:
-- Connect as a superuser ALTER ROLE app_user WITH PASSWORD 'new_secure_password'; -
Verify the role exists and has LOGIN privilege:
SELECT rolname, rolcanlogin FROM pg_roles WHERE rolname = 'app_user';If
rolcanloginisf, grant login:ALTER ROLE app_user WITH LOGIN; -
Check pg_hba.conf authentication method:
# Find the active pg_hba.conf psql -U postgres -c "SHOW hba_file;"Look for the line matching your connection. Common entries:
# TYPE DATABASE USER ADDRESS METHOD host all all 127.0.0.1/32 scram-sha-256 host all all 0.0.0.0/0 md5After editing, reload:
SELECT pg_reload_conf(); -
Fix SCRAM vs MD5 mismatch:
-- Check current password encryption setting SHOW password_encryption; -- If it shows 'scram-sha-256' but pg_hba.conf says 'md5', either: -- Option A: Change pg_hba.conf to scram-sha-256 (recommended) -- Option B: Set encryption to md5 and reset the password SET password_encryption = 'md5'; ALTER ROLE app_user WITH PASSWORD 'the_password'; -
Check .pgpass or connection string:
# .pgpass format: hostname:port:database:username:password cat ~/.pgpass # Ensure correct permissions chmod 600 ~/.pgpassFor connection strings, escape special characters:
postgresql://app_user:p%40ssw0rd@localhost:5432/mydb@â%40,#â%23,%â%25 -
Verify you're connecting to the right server:
-- After connecting, check where you are SELECT inet_server_addr(), inet_server_port(), current_user, current_database(); -
Check server logs for more detail:
# The server log often has a DETAIL line explaining what went wrong tail -20 /var/log/postgresql/postgresql-16-main.log
Common scenarios
In Docker and containers: The POSTGRES_PASSWORD environment variable only sets the superuser password on first initialization. If you change it in docker-compose.yml and restart without deleting the volume, the old password persists. Either drop the volume (docker volume rm ...) or connect and run ALTER ROLE.
After PostgreSQL major version upgrade: PostgreSQL 14 changed the default password_encryption from md5 to scram-sha-256. After upgrading, existing MD5 passwords still work if pg_hba.conf uses md5, but if you change pg_hba.conf to scram-sha-256, all users must reset their passwords.
In connection pools (PgBouncer, Pgpool-II): The pooler authenticates users independently. If the database password is changed but the pooler's userlist.txt or auth config isn't updated, connections through the pool fail with 28P01 even though direct connections work.
With cloud-managed databases (RDS, Cloud SQL, Azure): Cloud providers manage pg_hba.conf internally. If you get 28P01 on RDS, verify the password via the AWS console or aws rds modify-db-instance. For Cloud SQL, use gcloud sql users set-password.
Bytebase provides a secure credential management workflow that avoids sharing database passwords directly. For more on PostgreSQL access control, see Database Access Control Best Practices.