Skip to main content
DevOpsintermediate

FATAL: Peer Authentication Failed for User

Fix 'FATAL: Peer authentication failed for user postgres'. Peer auth ignores passwords entirely - find the pg_hba.conf line that matched, without trust.

10 min readUpdated August 2026

FATAL: Peer authentication failed for user "postgres" is PostgreSQL rejecting you on a rule that never looks at your password at all:

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

If you have been resetting the postgres password and retrying, that is why nothing changes. Peer authentication compares your operating system user name against the database user name you asked for, and refuses when they differ. Your OS user is not postgres, so it stops there.

Why This Happens

PostgreSQL decides how to authenticate you by reading pg_hba.conf top to bottom and using the first line that matches your connection type, database, user, and source address. Two rules follow from that, and both cause confusion:

  • There is no fall-through. If a line matches and authentication fails, PostgreSQL does not try later lines. Adding a scram-sha-256 line at the bottom of the file changes nothing if a peer line above it matched first.
  • local and host are different worlds. Omitting -h uses a Unix socket and matches local lines. Adding -h localhost or -h 127.0.0.1 forces TCP and matches host lines. These frequently have different auth methods, which is why one command works and the other fails.

A default pg_hba.conf contains something very close to this:

# TYPE  DATABASE  USER  ADDRESS       METHOD
local   all       all                 peer
host    all       all   127.0.0.1/32  scram-sha-256
host    all       all   ::1/128       scram-sha-256

That first line is the one catching you.

Fix 1: Become the postgres User (No Config Change)

This is the correct answer most of the time, and it needs no edits:

sudo -u postgres psql

sudo -u postgres makes your OS user genuinely postgres for that command, which is exactly what peer authentication is checking. You are now in a session and can do everything else from there.

Fix 2: Create a Role Matching Your Own OS User

If you are a developer who wants psql to just work, do not weaken the postgres superuser — give yourself your own role named after your OS user, so peer authentication succeeds honestly:

sudo -u postgres createuser --interactive --pwprompt "$USER"
sudo -u postgres createdb -O "$USER" "$USER"

Answer no to superuser unless you genuinely need it. Now this works with no host flag and no password:

psql

This keeps peer authentication intact — which is a real security property on a shared host — while removing the friction.

Fix 3: Use a Password Method Over TCP

If an application must connect with a password (which is normal — applications have no OS user on the database host), give it a TCP path with a password method rather than changing the local rule.

First, make sure the role actually has a password:

sudo -u postgres psql -c "ALTER ROLE appuser WITH PASSWORD '<strong-password>';"

Then confirm a host line covers the source address with scram-sha-256. Locate the file:

sudo -u postgres psql -c "SHOW hba_file;"

Add a rule that is as narrow as the application needs — specific database, specific role, specific address:

# TYPE  DATABASE  USER      ADDRESS         METHOD
host    appdb     appuser   10.0.3.0/24     scram-sha-256

Place it above any broader line that would match first. Then reload — no restart, no dropped connections:

sudo -u postgres psql -c "SELECT pg_reload_conf();"
# or: sudo systemctl reload postgresql

Use scram-sha-256, not md5. MD5-based authentication is legacy and weaker; upstream has been steering installations to SCRAM for several major versions.

Advertisement

Fix 4: Read the Log and Stop Guessing

This is the step that turns a frustrating afternoon into a two-minute fix, and almost nobody does it. Every authentication failure writes a DETAIL line to the server log naming the exact pg_hba.conf line that matched:

FATAL:  Peer authentication failed for user "postgres"
DETAIL:  Connection matched pg_hba.conf line 85: "local   all   all   peer"

There is no ambiguity left after reading that. The same mechanism explains the other confusing failures:

FATAL:  password authentication failed for user "postgres"
DETAIL:  User "postgres" has no password assigned.

FATAL:  password authentication failed for user "ghost"
DETAIL:  Role "ghost" does not exist.

Note the second one carefully: the client is told "password authentication failed" even when the role does not exist. That is deliberate, so an attacker cannot enumerate valid user names — but it means you can spend an hour resetting the password for a role that was never created. Only the log distinguishes them. See where PostgreSQL logs are stored for the path on your platform.

You can also inspect the rules as the server currently understands them, without opening the file:

SELECT line_number, type, database, user_name, address, auth_method
FROM pg_hba_file_rules
WHERE error IS NULL
ORDER BY line_number;

Match the line_number here to the one in the DETAIL message.

FATAL: pg_hba.conf rejects connection for host ... user ... database ... — a line matched and its method was reject, or no line matched at all. Add or reorder a rule for that exact combination.

could not connect to server: Connection refused / Is the server running on that host and accepting TCP/IP connections? — this is not authentication. Either the server is down, or it is not listening on that address. Check listen_addresses in postgresql.conf and confirm the port:

sudo -u postgres psql -c "SHOW listen_addresses;"
sudo ss -ltnp | grep 5432

FATAL: role "yourname" does not exist — you connected over a socket with no -U, so psql defaulted to your OS user name, and there is no such role. Either pass -U or create the role as in Fix 2.

Do Not "Fix" This With trust

The most common bad advice for this error is to change peer to trust. Understand what that does: trust accepts the connection unconditionally, with no credentials whatsoever, so anyone who can reach that socket or port connects as any database user they name — including superusers, and including on a host line, anyone who can reach the port over the network. It does not fix authentication; it removes it. Every case above has a real fix that keeps authentication in place.

Verify the Fix

# Socket path (matches 'local' rules)
psql -U postgres -c "SELECT current_user, inet_server_addr(), version();"

# TCP path (matches 'host' rules) — prove both work as intended
psql -h 127.0.0.1 -U appuser -d appdb -c "SELECT current_user;"

Then confirm the role holds only the privileges it should:

\du appuser

Prevent It Coming Back

  • Keep peer authentication for local administrative access. It is genuinely useful: it ties superuser access to OS-level access rather than to a password that can leak.
  • Give each developer a role named after their OS user so routine work never needs the postgres account.
  • Give applications their own least-privilege role over TCP with scram-sha-256, scoped to one database.
  • Order pg_hba.conf from most specific to least specific, and remember that the first match wins with no fall-through.
  • Reload rather than restart after editing — SELECT pg_reload_conf(); applies changes without dropping sessions.
  • Check pg_hba_file_rules after every edit to catch a syntax error before it locks you out.

Next Steps

Frequently Asked Questions

Find answers to common questions

PostgreSQL matched a pg_hba.conf line using the peer method, which ignores passwords completely and instead requires your operating system user name to equal the database user name you asked for. Your OS user is not 'postgres', so it refused. No password you set will change this.

Because peer authentication never looks at a password. The connection matched a 'local ... peer' line, so PostgreSQL compared your OS username to the requested database username and stopped there. You need to change how you connect or which pg_hba.conf line matches, not the password.

Run 'sudo -u postgres psql'. That makes your OS user actually be postgres for the duration of the command, which is exactly what peer authentication is checking. It requires no configuration change and no password.

Peer works only on local Unix-socket connections and compares OS username to database username. scram-sha-256 and md5 are password methods usable over both local and TCP connections. scram-sha-256 is the modern, stronger choice; md5 is legacy and should be migrated away from.

Omitting -h uses a Unix socket, which matches 'local' lines in pg_hba.conf. Adding -h localhost or -h 127.0.0.1 forces TCP, which matches 'host' lines instead. Those are different rules with potentially different auth methods, which is why one works and the other does not.

Look in the PostgreSQL server log. Every authentication failure logs a DETAIL line naming the exact file line number and its text, for example 'Connection matched pg_hba.conf line 85'. That single line removes all the guesswork about which rule applied.

Run SHOW hba_file; from any working session, or 'sudo -u postgres psql -c "SHOW hba_file;"'. It normally lives in the data directory on distributions that follow upstream layout, and under /etc/postgresql/// on Debian and Ubuntu.

No. A reload is enough — run SELECT pg_reload_conf(); or 'sudo systemctl reload postgresql'. A full restart drops every connection and is not required for pg_hba.conf or most postgresql.conf changes.

No. Trust means anyone who can reach the socket or port connects as any database user with no credentials at all, including superusers. It removes authentication rather than fixing it. Use sudo -u postgres, create a role matching your OS user, or configure scram-sha-256.

PostgreSQL deliberately returns the same message either way so an attacker cannot enumerate valid usernames. The server log tells the truth — it records DETAIL 'Role "x" does not exist' versus 'password authentication failed'. Always check the log before assuming the password is wrong.