TL;DR
Open /etc/postgresql/*/main/pg_hba.conf, change the peer authentication method to md5 (or scram-sha-256 for PostgreSQL 14+), then reload PostgreSQL.
# Before:
local all all peer
# After:
local all all md5
sudo systemctl reload postgresql
The Error
FATAL: Peer authentication failed for user "myapp"
You'll hit this when connecting to PostgreSQL over a local Unix socket while your OS username doesn't match the PostgreSQL role you're requesting. Worth noting: this has nothing to do with a wrong password. Peer auth never even checks one.
Root Cause
Under the hood, pg_hba.conf (host-based authentication) controls how every incoming connection gets authenticated. The peer method asks the OS: "who's the current user?" โ then checks if that name matches the requested PostgreSQL role.
Say you're logged in as ubuntu and run:
psql -U postgres
PostgreSQL sees OS user ubuntu, requested role postgres. No match โ denied. Most Debian/Ubuntu installs ship with this default:
local all postgres peer
local all all peer
Fine for system-level access via sudo -u postgres psql. But the moment your app connects using its own credentials, peer auth breaks it.
Fix Approaches
Option 1: Switch to md5 or scram-sha-256 (Most Common Fix)
First, locate your pg_hba.conf:
# Ask PostgreSQL directly:
sudo -u postgres psql -c "SHOW hba_file;"
# Typical paths:
# Debian/Ubuntu: /etc/postgresql/14/main/pg_hba.conf
# RHEL/CentOS: /var/lib/pgsql/14/data/pg_hba.conf
Open the file and update the local lines from peer to md5:
sudo nano /etc/postgresql/14/main/pg_hba.conf
# Change this:
local all all peer
# To this:
local all all md5
On PostgreSQL 14+, scram-sha-256 is the better choice โ it became the default password encryption in that version and is significantly stronger than MD5:
local all all scram-sha-256
Reload to apply without dropping active connections:
sudo systemctl reload postgresql
One more thing: make sure the database user actually has a password set.
sudo -u postgres psql
ALTER USER myapp WITH PASSWORD 'your_password_here';
\q
Option 2: Connect as the Matching OS User
Prefer keeping peer auth? Then the OS user running the command needs to match the PostgreSQL role:
# For the postgres superuser:
sudo -u postgres psql
# For an app-specific user:
sudo -u myapp psql -d myapp_db
Handy for one-off maintenance tasks. Useless for application connections that need to authenticate on their own.
Option 3: Scope the Change to a Specific User
Rather than switching everyone to password auth, add a targeted rule above the default catch-all. Rules in pg_hba.conf match top-to-bottom โ first match wins.
# pg_hba.conf โ specific rules go first:
local myapp_db myapp md5
local all all peer
Now myapp authenticates with a password against myapp_db, while the postgres superuser and everything else keeps peer auth.
Option 4: Use TCP Instead of Unix Socket
Here's a less obvious workaround. Unix socket connections follow the local rules in pg_hba.conf. TCP connections โ even to 127.0.0.1 โ follow the host rules, which usually default to md5:
psql -h 127.0.0.1 -U myapp -d myapp_db
Confirm your host lines allow password auth:
host all all 127.0.0.1/32 md5
host all all ::1/128 md5
pg_hba.conf Method Reference
- peer โ OS username must match DB role. No password checked. Local socket only.
- md5 โ Password required, stored as MD5 hash. Widely supported across all clients.
- scram-sha-256 โ Password required, stronger hashing. Needs PostgreSQL 10+ on both server and client.
- trust โ No authentication at all. Local dev only โ never production.
- reject โ Always deny. Useful for explicitly blocking specific IPs or users.
Verify the Fix
# Connect as your app user:
psql -U myapp -d myapp_db
# You should land at a prompt like:
# myapp_db=>
# Check whether the user has a password set:
sudo -u postgres psql -c "SELECT usename, passwd IS NOT NULL AS has_password FROM pg_shadow WHERE usename = 'myapp';"
# Confirm pg_hba rules loaded correctly:
sudo -u postgres psql -c "SELECT * FROM pg_hba_file_rules;"
No peer error on connect? You're done.
Tips
Switching to password-based auth means every database user needs an actual password โ don't skip that step. If you need to generate something strong, ToolCraft's Password Generator runs entirely in-browser with nothing sent to a server, which is worth knowing when you're creating database credentials.
Also: after editing pg_hba.conf, always use reload rather than restart. A reload applies the new config to incoming connections without touching existing ones. Restart is only needed for postgresql.conf changes โ and PostgreSQL will tell you which ones require it.
# Non-disruptive reload:
sudo systemctl reload postgresql
# Or from inside psql:
SELECT pg_reload_conf();

