Deploy Error Decoder

Postgres 'password authentication failed' — fix the credentials

Quick answer: Postgres rejected the credentials your app sent. The usual causes are a wrong password in DATABASE_URL, special characters in the password that were not URL-encoded (@ : / # break the URL), or the env var not loading. Test the exact credentials with psql; if that works, the bug is in how your app builds the connection string.

Not your exact error? Paste it into the Deploy Error Decoder →

What the error looks like

From the server log or the client - it names the user that was rejected:

FATAL:  password authentication failed for user "app"

# from a Node client (pg):
error: password authentication failed for user "app"
    at Parser.parseErrorMessage (.../pg-protocol/...)
  code: '28P01'

SQLSTATE 28P01 is "invalid_password." The credentials reached Postgres and were refused - so the host and port are fine; the username or password is wrong, or not encoded the way you think.

Why it happens

Wrong password or user

The password in DATABASE_URL is wrong, or you are connecting as the wrong user.

Special chars not URL-encoded

A password with @ : / or # breaks the URL, so the parsed password is wrong.

Env var did not load

.env was not read or the variable name is wrong, so an empty or default password is sent.

pg_hba.conf / auth method

The required method (scram-sha-256 vs md5, or password vs trust) does not match how the client connects.

Diagnose it in three steps

1

Test the exact credentials with psql

psql "postgresql://app:thepassword@db:5432/myapp"
# works? the creds are fine - the bug is how your app builds the URL.
# fails? the username or password is genuinely wrong.
2

Print what your app actually sends

const u = new URL(process.env.DATABASE_URL);
console.log('user:', u.username, 'pass length:', u.password.length);
// length 0 = env var not loaded; wrong length = bad encoding.
3

Check for special characters

# if the password has @ : / # space, it MUST be URL-encoded in a URL:
# p@ss/word  ->  p%40ss%2Fword
The real fix

Correct, encode, or pass discrete fields

Set the right user and password, and if you use a DATABASE_URL, URL-encode any special characters. The most robust option is to skip the URL and pass discrete connection fields, which removes encoding mistakes entirely.

# URL form - encode special characters:
DATABASE_URL=postgresql://app:p%40ss%2Fword@db:5432/myapp

// or discrete fields (no URL-encoding needed):
const { Pool } = require('pg');
const pool = new Pool({
  user: 'app',
  password: process.env.PGPASSWORD,   // raw value, no encoding
  host: 'db', port: 5432, database: 'myapp',
});

# if pg_hba.conf is the issue, align the method and reload:
# host  myapp  app  0.0.0.0/0  scram-sha-256
sudo systemctl reload postgresql

After changing a role's password with ALTER USER app WITH PASSWORD '...', make sure every instance uses the new value - a stale password on one node looks like an intermittent auth failure.

How Infraveil handles this

Consistent DB credentials across your fleet

Intermittent auth failures are usually a config-consistency problem - one instance has a stale or mis-encoded credential. On your own servers, Infraveil distributes database credentials and config consistently across the services you run, so every instance connects with the same value, secret rotation is coordinated, and changes are approval-gated and recorded.

The same DB credentials on every instance, on infra you control
Connection failures surfaced with context in one view
Credential rotation coordinated, approval-gated, and recorded

Frequently asked questions

Why does psql work but my app fails?

The app builds the connection string differently - most often a special character in the password not URL-encoded in DATABASE_URL, or the env var did not load. Print the exact string the app uses (password masked) and compare.

How do I handle special characters in the password?

URL-encode them in a DATABASE_URL: @ becomes %40, : becomes %3A, / becomes %2F, # becomes %23. Or pass user and password as discrete fields to the client to avoid encoding entirely.

What is pg_hba.conf's role?

It controls which auth method Postgres requires per host and user. A mismatch (scram-sha-256 vs md5, or password vs none) fails auth even with the right password. Align it with how the app connects and reload Postgres.

Could it be the wrong user, not the password?

Yes - the error names the rejected user. Confirm that user exists, has a password set, and has privileges on the target database. Connecting as the wrong user is a common cause.