FATAL: password authentication failed for user "postgres" — and the password you
typed is the one in your docker run line or compose file. The postgres
image reads POSTGRES_PASSWORD only when it creates a new database. Your volume
still holds the database made with the old password. Set the new one inside PostgreSQL, or
throw the volume away.
The one-line fix is docker exec into the container and
ALTER USER postgres WITH PASSWORD '...'. The psql inside the container
connects through the local socket, which needs no password, so it works even while every
connection from outside fails.
The error
$ docker run -d --name fix3-dpg-pw -e POSTGRES_PASSWORD=new-dev-password -p 127.0.0.1:15432:5432 -v fix3-dpg-pwdata:/var/lib/postgresql postgres:18
$ docker run --rm --name fix3-dpg-cli -e PGPASSWORD=new-dev-password postgres:18 psql -h host.docker.internal -p 15432 -U postgres -c "SELECT current_user;"
psql: error: connection to server at "host.docker.internal" (192.168.65.254), port 15432 failed: FATAL: password authentication failed for user "postgres"
The same connection from a .NET app with Npgsql, first line of the exception:
Unhandled exception. Npgsql.PostgresException (0x80004005): 28P01: password authentication failed for user "postgres"
And the server's side, in docker logs:
2026-10-02 01:30:24.227 UTC [36] FATAL: password authentication failed for user "postgres"
2026-10-02 01:30:24.227 UTC [36] DETAIL: Connection matched file "/var/lib/postgresql/18/docker/pg_hba.conf" line 128: "host all all all scram-sha-256"
Why it happens
The image's entrypoint script runs before the server. On an empty data directory it runs
initdb and sets the postgres password from
POSTGRES_PASSWORD. On a directory that already holds a database it prints
PostgreSQL Database directory appears to contain a database; Skipping initialization
and starts the server; the variable is never read again. So the container's environment says
new-dev-password, while the role inside the volume still has the first one. The
old password kept working the whole time.
You only notice from outside. The pg_hba.conf the image writes trusts the local
socket and 127.0.0.1 inside the container, and requires scram-sha-256 for
everything else (line 128 above). That is why docker exec ... psql logs in fine
while your app, or any client that comes in through the published port, is refused.
The fix
docker exec fix3-dpg-pw psql -U postgres -c "ALTER USER postgres WITH PASSWORD 'new-dev-password';"
It printed ALTER ROLE. The .NET app then printed Connected as postgres,
psql over TCP connected with the new password, and the old password was refused.
Nothing else in the database changes, and no restart is needed.
If the database holds nothing you need, recreating the volume works too, because the entrypoint initialises again:
docker stop fix3-dpg-pw
docker rm fix3-dpg-pw
docker volume rm fix3-dpg-pwdata
docker run -d --name fix3-dpg-pw -e POSTGRES_PASSWORD=new-dev-password -p 127.0.0.1:15432:5432 -v fix3-dpg-pwdata:/var/lib/postgresql postgres:18
The log showed PostgreSQL init process complete; ready for start up. and the new
password connected. Removing the volume deletes the database, so use this only on a throwaway
development container.
How it was reproduced
Docker Desktop 4.91.0 (engine 29.8.0) on Windows 11, image postgres:18 (18.4),
port 15432 published on 127.0.0.1. The first container ran with
POSTGRES_PASSWORD=first-dev-password on a named volume; it was stopped, removed and
started again on the same volume with new-dev-password. Clients: psql
18.4 in a second container connecting through host.docker.internal, and a .NET 10
console app (SDK 10.0.401, Npgsql 10.0.3) on the host. Both failed with the new password and
connected with the old one until the ALTER USER. Names beginning
fix3-dpg- are this test's own container and volume; use yours.
Frequently asked
- Why does postgres in Docker say password authentication failed when the password is right?
- Because POSTGRES_PASSWORD is applied only when the image creates a new database. If the container reuses a volume made earlier, the postgres role still has the password from that first start, whatever the variable now says.
- How do I change the postgres password in a Docker container?
- Run docker exec on the container with psql -U postgres -c and an ALTER USER postgres WITH PASSWORD statement. psql inside the container uses the local socket, which the image trusts, so it does not need the old password.
- Why does docker exec psql work but my app gets 28P01?
- The image's pg_hba.conf trusts connections from inside the container and requires a scram-sha-256 password for every other address. Your app connects through the published port, so its password is checked; docker exec psql is not.
More decoded errors in the Fixes category. The same entrypoint check explains another first-start failure: Database is uninitialized and superuser password is not specified.