Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Postgres By James Joyner IV · · 10 min read

PostgreSQL Error Guide: 'password authentication failed for user' Login Fails

Fix PostgreSQL 'FATAL: password authentication failed for user': diagnose wrong passwords, pg_hba.conf md5/scram method mismatches, missing LOGIN roles, and encryption mismatches.

  • #postgres
  • #troubleshooting
  • #errors
  • #authentication

Overview

PostgreSQL returns this error when a client presents credentials that the server cannot verify against the matching pg_hba.conf rule. The connection reached the server, found a host-based authentication line, attempted a password method (md5, scram-sha-256, or password), and the password check failed. Authentication, not connectivity, is the problem here.

You will see this in the client output and the PostgreSQL log:

FATAL:  password authentication failed for user "appuser"

It occurs at login time, after the network connection succeeds and a pg_hba.conf rule is matched. A subtle point: PostgreSQL deliberately returns the same message whether the password is wrong, the role lacks a stored password, or the stored password is the wrong encryption type — so the obvious “wrong password” is only one of several real causes.

Symptoms

  • Login fails with FATAL: password authentication failed for user "<name>".
  • The same credentials may work from one host or database but not another.
  • The server log records the failed line with the auth method that was attempted.
  • A role that worked yesterday fails after a pg_hba.conf or password_encryption change.
psql "host=db.internal user=appuser dbname=appdb" -c 'select 1'
psql: error: connection to server at "db.internal" (10.0.4.10), port 5432 failed:
FATAL:  password authentication failed for user "appuser"
sudo tail -5 /var/lib/pgsql/data/log/postgresql.log
LOG:  connection received: host=10.0.4.30 port=51884
FATAL:  password authentication failed for user "appuser"
DETAIL:  Connection matched pg_hba.conf line 92: "host  appdb  appuser  10.0.4.0/24  md5"

The DETAIL line naming the matched pg_hba.conf rule is the single most useful clue — it tells you which rule and method are in play.

Common Root Causes

1. The password is simply wrong

The most common cause: the client is sending a stale or mistyped password, often from an environment variable, .pgpass, or a secret that drifted from what the role actually has.

# Confirm which password source the client is using
echo "PGPASSWORD set: ${PGPASSWORD:+yes}"
grep -H "db.internal" ~/.pgpass 2>/dev/null
PGPASSWORD set: yes
/home/deploy/.pgpass:db.internal:5432:appdb:appuser:Old-Passw0rd

A .pgpass entry with an outdated password silently overrides what you think you are typing. Reset the role password to a known value and retry to rule this in or out.

2. pg_hba.conf method mismatch (md5 vs scram-sha-256)

If the role’s password is stored as SCRAM but the matching pg_hba.conf line specifies md5 (or vice versa), authentication can fail depending on versions and the stored format.

grep -nE '^(host|local).*appuser' /var/lib/pgsql/data/pg_hba.conf
92:host    appdb    appuser    10.0.4.0/24    md5
93:host    all      all        0.0.0.0/0      scram-sha-256

If the password was stored under scram-sha-256 but line 92 demands md5, the md5 challenge cannot validate a SCRAM verifier. Align the method to how the password is actually stored (see cause 6).

3. The role does not exist or has no LOGIN privilege

A typo in the username, or a role created with NOLOGIN (the default for CREATE ROLE without LOGIN), produces the same authentication failure.

SELECT rolname, rolcanlogin
FROM pg_roles
WHERE rolname = 'appuser';
 rolname | rolcanlogin
---------+-------------
 appuser | f
(1 row)

rolcanlogin = f means the role cannot log in at all. An empty result means the role name is wrong. Grant login with ALTER ROLE appuser LOGIN;.

4. The role has no password set (NULL password)

A role created without a password, or one whose password was cleared, has a NULL rolpassword. Any password the client sends will fail the check.

SELECT rolname,
       rolpassword IS NULL AS password_is_null,
       left(rolpassword, 14) AS pw_prefix
FROM pg_authid
WHERE rolname = 'appuser';
 rolname | password_is_null |   pw_prefix
---------+------------------+----------------
 appuser | t                |
(1 row)

password_is_null = t means no password is stored; set one with ALTER ROLE appuser PASSWORD '...';. (Reading pg_authid requires superuser.)

5. Wrong database in the connection string matches a different hba rule

pg_hba.conf rules are matched on database name as well as user and source address. Connecting to a different database can match a stricter rule (or a reject line) and fail, even with correct credentials.

grep -nE '^(host|local)' /var/lib/pgsql/data/pg_hba.conf | head
40:local   all        all                          peer
55:host    appdb      appuser    10.0.4.0/24        md5
56:host    reportdb   appuser    10.0.4.0/24        reject
70:host    all        all        0.0.0.0/0          scram-sha-256

Connecting appuser to reportdb hits the reject on line 56, while appdb works on line 55. The error looks identical to a bad password but is really a rule-ordering/database issue.

6. password_encryption mismatch (scram stored vs md5 expected)

When password_encryption is changed (the modern default is scram-sha-256), existing passwords keep their old encoding until the password is reset. A role with an md5-encoded password under a scram-sha-256 hba line, or the reverse, fails to authenticate.

SHOW password_encryption;

SELECT rolname,
       CASE
         WHEN rolpassword LIKE 'SCRAM-SHA-256$%' THEN 'scram-sha-256'
         WHEN rolpassword LIKE 'md5%'            THEN 'md5'
         ELSE 'plain/none'
       END AS stored_as
FROM pg_authid
WHERE rolname = 'appuser';
 password_encryption
---------------------
 scram-sha-256

 rolname | stored_as
---------+-----------
 appuser | md5
(1 row)

The server now expects SCRAM, but appuser still has an md5 verifier stored. Re-setting the password under the new password_encryption regenerates the correct verifier.

Diagnostic Workflow

Step 1: Read the server log for the matched hba line

sudo grep -A1 'password authentication failed' \
  /var/lib/pgsql/data/log/postgresql.log | tail -4

The DETAIL: Connection matched pg_hba.conf line N tells you exactly which rule and method are being applied. Everything else flows from that line.

Step 2: Verify the role exists and can log in

SELECT rolname, rolcanlogin, rolvaliduntil
FROM pg_roles
WHERE rolname = 'appuser';

A missing row (wrong name), rolcanlogin = f (NOLOGIN), or a past rolvaliduntil (expired password) each cause the same error. Fix with ALTER ROLE appuser LOGIN; or ALTER ROLE appuser VALID UNTIL 'infinity';.

Step 3: Check how the password is stored vs what hba expects

SHOW password_encryption;

SELECT rolname,
       rolpassword IS NULL AS is_null,
       CASE WHEN rolpassword LIKE 'SCRAM-SHA-256$%' THEN 'scram'
            WHEN rolpassword LIKE 'md5%' THEN 'md5' ELSE 'none' END AS stored_as
FROM pg_authid WHERE rolname = 'appuser';

A NULL password, or a stored_as that does not match the hba line’s method, is the cause. Reset the password (Step 5) to regenerate a matching verifier.

Step 4: Confirm the database and source address match the intended rule

grep -nE '^(host|local).*(appuser|all)' /var/lib/pgsql/data/pg_hba.conf

Ensure the database and address columns of the intended rule actually cover the database name and client IP you are connecting from, and that no earlier reject/stricter line shadows it. Rules are evaluated top to bottom; the first match wins.

Step 5: Reset the password and reload, then retry

-- As a superuser; this re-encodes under the current password_encryption
ALTER ROLE appuser WITH LOGIN PASSWORD 'NewStr0ng-Pass';
# After editing pg_hba.conf, reload (no restart needed for hba changes)
sudo -u postgres psql -c 'SELECT pg_reload_conf();'

Resetting the password under the active password_encryption is the single fix that resolves NULL-password, encryption-mismatch, and stale-credential cases at once.

Example Root Cause Analysis

After upgrading the cluster, the reporting service starts failing every connection with FATAL: password authentication failed for user "reporter", even though the password in its secret is unchanged and correct.

The server log points at the rule:

FATAL:  password authentication failed for user "reporter"
DETAIL:  Connection matched pg_hba.conf line 70: "host all all 0.0.0.0/0 scram-sha-256"

The matched line uses scram-sha-256. Checking how the password is actually stored:

SHOW password_encryption;
SELECT rolname,
       CASE WHEN rolpassword LIKE 'SCRAM-SHA-256$%' THEN 'scram'
            WHEN rolpassword LIKE 'md5%' THEN 'md5' ELSE 'none' END AS stored_as
FROM pg_authid WHERE rolname = 'reporter';
 password_encryption
---------------------
 scram-sha-256

 rolname  | stored_as
----------+-----------
 reporter | md5

The upgrade flipped password_encryption to scram-sha-256 and the hba line to match, but reporter’s password was set years ago and is still stored as an md5 verifier. An md5 hash cannot satisfy a SCRAM exchange, so every login fails — the credential itself was never wrong.

Fix: re-set the password (the value can be identical) so it is re-encoded under SCRAM:

ALTER ROLE reporter WITH PASSWORD 'same-secret-value-as-before';
SELECT CASE WHEN rolpassword LIKE 'SCRAM-SHA-256$%' THEN 'scram' ELSE 'md5' END
FROM pg_authid WHERE rolname = 'reporter';
 case
-------
 scram

With a SCRAM verifier now stored, the reporting service authenticates against line 70 and reconnects normally.

Prevention Best Practices

  • Standardize on scram-sha-256 for password_encryption and pg_hba.conf, and re-set every role’s password once after switching so no stale md5 verifiers linger.
  • Keep pg_hba.conf rules ordered from most specific to least specific, and avoid broad reject lines that can shadow legitimate database-specific access.
  • Store credentials in one source of truth (a secret manager) and avoid duplicating them in .pgpass, environment variables, and config files where they drift apart.
  • Always create application roles with explicit LOGIN PASSWORD ... and a VALID UNTIL policy you actually monitor, so expired or NOLOGIN roles surface before users hit them.
  • Test the full connection string (host, database, user) from the real client host after any hba change, since the matched rule depends on all three.
  • When triaging a failure, the server log’s DETAIL: Connection matched pg_hba.conf line N is authoritative — the free incident assistant can map that log line straight to the misconfigured rule or method.

Quick Command Reference

# Server log: which hba line matched?
sudo grep -A1 'password authentication failed' \
  /var/lib/pgsql/data/log/postgresql.log | tail -4

# Inspect hba rules for a user
grep -nE '^(host|local).*(appuser|all)' /var/lib/pgsql/data/pg_hba.conf

# Reload after editing pg_hba.conf (no restart needed)
sudo -u postgres psql -c 'SELECT pg_reload_conf();'
-- Does the role exist and can it log in?
SELECT rolname, rolcanlogin, rolvaliduntil FROM pg_roles WHERE rolname = 'appuser';

-- How is the password stored vs what hba expects? (superuser only)
SHOW password_encryption;
SELECT rolname, rolpassword IS NULL AS is_null,
       CASE WHEN rolpassword LIKE 'SCRAM-SHA-256$%' THEN 'scram'
            WHEN rolpassword LIKE 'md5%' THEN 'md5' ELSE 'none' END AS stored_as
FROM pg_authid WHERE rolname = 'appuser';

-- Re-encode the password under the current password_encryption
ALTER ROLE appuser WITH LOGIN PASSWORD 'NewStr0ng-Pass';

Conclusion

FATAL: password authentication failed for user means the connection reached a pg_hba.conf rule but the password check failed — and PostgreSQL deliberately reuses this message for several distinct causes. The usual root causes:

  1. The password is simply wrong or stale (often a drifted .pgpass/secret).
  2. A pg_hba.conf method mismatch between md5 and scram-sha-256.
  3. The role does not exist or was created NOLOGIN.
  4. The role has no password set (NULL rolpassword).
  5. The connection’s database matches a stricter or reject hba rule.
  6. A password_encryption change left an md5 verifier under a SCRAM rule (or vice versa).

Start from the log’s DETAIL: Connection matched pg_hba.conf line N: it pins down the rule and method, after which verifying the role and re-setting the password under the current encryption resolves the large majority of cases. More PostgreSQL guides are in the Postgres category.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.