Blog
3 min read

Postgres "password authentication failed for user": How to Fix It

Postgres rejected the username or password your app sent. The real causes — wrong password in the connection string, special characters not URL-encoded, a Docker volume that kept an old password, the wrong user or host, pg_hba.conf rules — and how to reset the password safely.

FATAL: password authentication failed for user "postgres"

Postgres received your connection, checked the username and password, and said no. The error is deliberately vague (it won't tell an attacker whether the user exists), so you have to check the likely causes one by one.

Cause 1: the password in your connection string is wrong

Obvious, but check it carefully. Your app probably reads a DATABASE_URL like:

postgresql://app_user:s3cret@localhost:5432/myapp
  • Is the app reading the .env file you think it is? Print the user and host (not the password) at start-up to confirm. (Environment variable undefined?)
  • Is an old value set in your shell or hosting dashboard, overriding the file?

(Postgres connection strings explained)

Cause 2: special characters in the password

If your password contains @, :, /, #, % or ?, it breaks the URL format — the parser splits it in the wrong place and sends the wrong password.

Percent-encode those characters in the URL:

Character Encoded
@ %40
: %3A
/ %2F
# %23
% %25

So password p@ss#1 becomes p%40ss%231 in the connection string. Or generate passwords from letters and digits only.

Cause 3: Docker kept the old password

A very common one. With the official Postgres image, POSTGRES_PASSWORD is used only the first time the database is created. If you later change it in docker-compose.yml, the existing data volume still has the old password.

Options:

  • Use the old password, or

  • Change it inside the database (below), or

  • If the data is disposable, delete the volume and start fresh:

    docker compose down -v    # ⚠ deletes the database data
    docker compose up -d
    

(Docker volumes vs bind mounts, Docker Compose for local development)

Cause 4: connecting to a different Postgres

You have a Postgres installed on your machine and one in Docker, both on port 5432. Your app connects to the local one, which has different users and passwords. Check what's listening on the port, and consider mapping the container to 5433. (Docker port already allocated)

Similarly, localhost vs a remote host, or production vs staging credentials mixed up.

Cause 5: the user doesn't exist

The same error appears if the user doesn't exist at all. List users (in psql, as a superuser):

\du

Create one if needed:

CREATE ROLE app_user WITH LOGIN PASSWORD 'a-long-random-password';
GRANT CONNECT ON DATABASE myapp TO app_user;

(Postgres roles and permissions)

Cause 6: pg_hba.conf rules

pg_hba.conf controls how each user may log in from each address. If it requires scram-sha-256 but the user's password was stored with an older method (md5), or the rule for your address uses a method you don't expect, logins fail. After changing it, reload Postgres. Managed providers handle this for you.

Resetting a password

If you can get into Postgres as a superuser (on a server, usually via the postgres system user):

sudo -u postgres psql
ALTER USER app_user WITH PASSWORD 'new-long-random-password';

In a Docker container:

docker compose exec db psql -U postgres

Then update the connection string everywhere it's used.

Keep it secure

  • Use a long random password, and a separate user for your app (not postgres).
  • Keep the connection string in environment variables, never in Git. (Secrets management)
  • Don't expose port 5432 to the internet. (UFW firewall basics)

EasySpawn creates your app's database and its credentials for you, and wires the connection string into your app's environment, so there's no password to mistype. See how it works or join the waitlist.

Related: Postgres Connection Strings Explained · ECONNREFUSED 127.0.0.1:5432 · Postgres Roles and Permissions · What Is PostgreSQL?

Keep reading