PostgreSQL

psql: FATAL: Peer authentication failed for user "postgres"

The error fires when PostgreSQL's peer auth check compares the OS username to the database role and they differ — common after sudo-ing into psql or in local dev. Fix it by matching users, or by switching the local auth method to scram-sha-256 with a real password.

Mahdi Ben RhoumaMahdi Ben Rhouma
Updated
6 min

You fire up local PostgreSQL, type psql -U postgres, and the connection dies with:

text
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432"
failed: FATAL:  Peer authentication failed for user "postgres"

The Stack Overflow thread Q18664074 has the diagnosis: peer authentication compares the OS username to the database role, and they don't match. You ran psql as your own OS user (e.g. mahdi) but asked to connect as role postgres. Peer auth says no.

This is a local-dev issue, not a production one — peer auth is only the default for local connections in pg_hba.conf. Here are the two correct fixes.

Fix 1 — Connect as the matching OS user#

The cleanest fix: become the user PostgreSQL expects.

bash
sudo -u postgres psql

postgres is both the OS account the server runs as and the default superuser role. Peer auth now sees OS user postgres connecting as role postgres — match, allowed.

If you need your own database role, create it and connect as yourself:

bash
sudo -u postgres createuser --superuser $USER
sudo -u postgres createdb $USER
psql   # now peer auth matches: OS user mahdi -> role mahdi

Fix 2 — Switch the local method to scram-sha-256#

If you want to connect as role postgres from your own OS user with a password (common for app dev), change the auth method. The order matters: set the password while peer auth still lets you in, then switch the method. The steps below were reproduced on Debian 12 with the distribution's PostgreSQL 15.19 package on 2 October 2026.

Step 1 — Set a password for the role, and locate pg_hba.conf#

Peer auth never used a password, so the role likely has none. The password authentication docs are explicit: if no password has been set up for a user, password authentication will always fail for that user. Set it now, while sudo -u postgres psql still works through peer:

bash
sudo -u postgres psql -c "ALTER USER postgres PASSWORD 'a-strong-dev-password';"
sudo -u postgres psql -c 'SHOW hba_file;'

In the reproduction, switching the method first and setting the password afterwards locked the postgres account out of its own socket: sudo -u postgres psql then failed with fe_sendauth: no password supplied, and with any guessed password with password authentication failed for user "postgres".

Step 2 — Edit every local line that matches the role#

PostgreSQL uses the first pg_hba.conf record that matches the connection type, database and user; the pg_hba.conf docs state there is no fall-through to later records. On Debian and Ubuntu the packaged file has a dedicated line for the postgres role above the general one. This is the Debian 12 default:

text
local   all             postgres                                peer
local   all             all                                     peer
host    all             all             127.0.0.1/32            scram-sha-256
host    all             all             ::1/128                 scram-sha-256

Changing only the local all all line has no effect for role postgres: in the reproduction, psql -U postgres run as another OS user still failed with Peer authentication failed for user "postgres", because the first line matched. Change both:

text
local   all             postgres                                scram-sha-256
local   all             all                                     scram-sha-256
Do not use trust

Setting the method to trust makes the error go away by disabling auth entirely — any local user can connect as any role, including the superuser. Fine on an isolated throwaway VM, dangerous on any shared or developer machine. Use scram-sha-256 and a real password.

Step 3 — Reload PostgreSQL#

bash
sudo systemctl reload postgresql

Reload is enough — pg_hba.conf changes do not need a full restart.

Step 4 — Check over the socket, not over TCP#

Run psql -U postgres with no -h: it connects over the Unix socket, which is what the local lines govern. It now prompts for the password and succeeds; a wrong password fails with password authentication failed for user "postgres".

Do not test with psql -U postgres -h localhost. That connects over TCP and matches the host lines, which are already scram-sha-256 on Debian 12: in the reproduction it succeeded with the password before pg_hba.conf was touched, so it proves nothing about the local edit.

Supabase local dev#

Supabase's local stack (the supabase CLI with supabase start) runs Postgres in a container with its own auth setup — peer auth is not the issue there. The usual gotchas:

  • Use the exact database URL that supabase status prints — by default postgresql://postgres:postgres@127.0.0.1:54322/postgres, on port 54322, not 5432.
  • Studio runs on 54323. Use the DB port, not the studio port, in your connection string.
  • supabase stop keeps your local data: the CLI docs state that local data "are backed up to docker volume", and only supabase stop --no-backup deletes the data volumes. A password you changed with ALTER USER therefore survives a stop/start — restarting is not a way to reset it.

Once the database connects, the next problems are usually in the app: RLS, keys, cookies and pooling are covered in common Next.js + Supabase production mistakes.

Why peer auth exists#

Peer auth lets PostgreSQL delegate authentication to the OS: if you are already logged in as user mahdi on a secure multi-user box, that is proof enough — no password to leak. It is secure and zero-config when the OS user and PG role match by convention. The error is the system correctly refusing a mismatch, not a bug.

Common mistakes#

  • trust to make it stop — disables auth; use scram-sha-256 instead.
  • Editing the wrong pg_hba.conf — there can be several (Debian vs Homebrew vs Docker). Confirm with SHOW hba_file; before editing.
  • Forgetting to reload — pg_hba.conf is re-read on reload, not on every connection; run systemctl reload postgresql.
  • Setting the password last — once the matching local line is scram-sha-256, a role with no password cannot log in at all (fe_sendauth: no password supplied, or password authentication failed), including through sudo -u postgres psql. Set it first.
  • Editing only the local all all line on Debian/Ubuntu — the local all postgres line above it still matches first.
  • Port confusion in Supabase local — DB is 54322, not 5432.

Official references: PostgreSQL — Client Authentication (pg_hba.conf), Auth Methods — Peer Authentication. For a related connection issue on Apple Silicon, see Prisma can't reach database server.

The host-connection equivalent: ident authentication and pg_ident.conf#

Everything above concerns peer auth, which only applies to local connections — the ones made over a Unix domain socket, with no host or port in the connection string. There's a separate but conceptually identical method for TCP connections (host lines in pg_hba.conf): ident. Where peer asks the local kernel who owns the process making the socket connection, ident asks a remote ident service (defined by RFC 1413) running on the connecting machine who owns that TCP connection. It fails for the same underlying reason — the identity PostgreSQL is told doesn't match the role being requested — but it produces a distinct error, Ident authentication failed for user "...":

text
# pg_hba.conf — host line using ident
# TYPE  DATABASE  USER  ADDRESS       METHOD
host    all       all   192.168.1.0/24 ident

Both peer and ident accept a map= option on the line; only then does PostgreSQL consult pg_ident.conf for user-name mapping, letting an OS user log in as a differently-named PostgreSQL role (user name maps). Without a map, the OS name must equal the role name. In practice, ident over the network is rare today: most production setups use scram-sha-256 for host connections precisely to avoid depending on a remote identd service most systems don't run. If a host line is set to ident and nothing is listening on the remote machine's ident port, the connection fails outright rather than falling through to a different check — switching that line to scram-sha-256, the same method Fix 2 above uses for local, resolves it identically. Once a host line uses password auth, the connection can still fail on a separate check afterward — see Fix: password authentication failed for user "postgres" for that follow-on error.

Peer auth inside a Docker container#

With the official postgres Docker image, docker exec -it <container> psql -U postgres works, but not because of a user match. The image's Dockerfile sets no USER, so docker exec runs as root; it works because, as the image documentation says, the image sets up trust authentication locally. Checked on postgres:18 on 2 October 2026: whoami inside docker exec printed root, the generated pg_hba.conf starts with these lines, and even docker exec -u nobody … psql -U postgres connected:

text
local   all             all                                     trust
host    all             all             127.0.0.1/32            trust
host    all             all             ::1/128                 trust
host all all all scram-sha-256

So a peer error inside a container means the server was not set up by the official image's entrypoint, typically an image that installs the distribution's postgresql package, which keeps the Debian peer lines shown in Fix 2. Apply Fix 2 inside that container, or connect from the app over TCP (host=db port=5432, the compose service name) with a password; from another container, the last line above means a password is required. For the container networking model this depends on, see Docker Tutorial 2026: Dev Environment with Compose.

Frequently Asked Questions

|

Have more questions? Contact us

Still stuck? Paste your error.

Paste the error message or stack trace — we check it against every fix and tool on the site.

Matching happens in your browser. When you search, a cleaned error signature is sent so we can spot errors we do not cover yet — never the raw text, your IP address or your e-mail. Do not paste passwords or keys. Details

Written by

Mahdi Ben Rhouma
Mahdi Ben Rhouma

Full-Stack Dev — Next.js & Supabase

Solo developer building SaaS products with Next.js and Supabase. Writing about production patterns the official docs skip.

Remote

One email a month — the latest explained errors

What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.