PostgreSQL Roles and Peer Authentication
Create a role with your own name and the connection that failed a moment ago succeeds with no password at all. `pg_hba.conf` explains why - and why the same role needs a password over TCP.
Foundations Guide 2 of 47 Beginner
- OSUbuntu 26.04 LTS (resolute)
- PostgreSQL18.6-0ubuntu0.26.04.1
- PackagingDebian cluster layout
- TimeAbout 14 min
- Reviewed27 August 2026
Written against the versions above. scram-sha-256 has been the default password method since PostgreSQL 14. Older clients expecting md5 need upgrading rather than downgrading the server.
| Server Name | IP Address | OS | Roles | CPU | RAM | HDD |
|---|---|---|---|---|---|---|
| db-a01 | 192.168.0.81 | Ubuntu 26.04 LTS | Primary / Source / Replica Set Member 1 | 2 Core | 4 GB | 50 GB |
Before you start
- PostgreSQL installed, with
sudo -u postgresaccess.
-
Create a role named after your OS user
A role in PostgreSQL is both what other databases call a user and what they call a group - one object type for both, distinguished only by whether it has
LOGIN.LOGINmakes it usable as a connection identity.CREATEDBlets it create databases without being a superuser, which is what an administrative-but-not-root account normally needs. The password matters only for TCP connections, which the last step of this guide explains.bash Example session sudo -u postgres psql -c "CREATE ROLE sysadmin LOGIN CREATEDB PASSWORD 'S7rong-Pass!2026'" ; echo "exit=$?"ERROR: role "sysadmin" already existsexit=1Expected result
CREATE ROLEandexit=0.Success conditionA role exists with the same name as your OS user.
-
Connect as yourself, with no password
The command that failed with
role does not existnow works.current_useris sysadmin, andinet_server_addr() IS NULLreturns t - true, meaning there is no server IP address for this connection because it came over a unix socket rather than TCP.No password was typed and none is stored for this purpose. Peer authentication asked the operating system who you are and believed it, which is safe precisely because only the kernel can answer that question over a local socket.
bash Example session psql -d postgres -c "SELECT current_user, current_database(), inet_server_addr() IS NULL AS via_socket" current_user | current_database | via_socket--------------+------------------+------------ sysadmin | postgres | t(1 row)Expected result
sysadmin, databasepostgres, andvia_socket= t.Success conditionYou can use PostgreSQL as your own user without a password.
-
Read the file that decided all of it
pg_hba.conf- host-based authentication - is read top to bottom and the first matching line wins. Comments stripped, there are seven lines and they are worth reading as a set.The two
locallines usepeer: any user, over the unix socket, authenticated by their OS identity. That is what the previous step used.The
hostlines cover127.0.0.1/32and::1/128withscram-sha-256- TCP, even to the same machine, requires a password. The OS identity is not available over TCP, so peer is not an option.The
replicationlines are separate because replication connections are a distinct database name in this file. The replication track edits exactly these.So one role behaves two ways depending on the transport, and this file is the only place that is written down.
bash Example session sudo grep -vE "^#|^$" /etc/postgresql/18/main/pg_hba.conflocal all postgres peerlocal all all peerhost all all 127.0.0.1/32 scram-sha-256host all all ::1/128 scram-sha-256local replication all peerhost replication all 127.0.0.1/32 scram-sha-256host replication all ::1/128 scram-sha-256Expected resultTwo
local ... peerlines, fourhost ... scram-sha-256, and the replication entries.Success conditionYou can predict how a given connection will be authenticated.
-
Read the connection you actually have
\conninfois psql's own summary and answers several questions at once.Socket Directory: /var/run/postgresqlrather than a host - a local socket, matching thetfrom two steps ago.Password Used: falseconfirms peer did the work.SSL Connection: falsefollows from being a socket.Superuser: offis the one to notice.sysadminhasCREATEDBbut is not a superuser, which is correct - a role that can create databases but cannot read every table or disable constraints is a much better daily identity thanpostgres.bash Example session psql -d postgres -c "\conninfo" Connection Information Parameter | Value----------------------+--------------------- Database | postgres Client User | sysadmin Socket Directory | /var/run/postgresql Server Port | 5432 Options | Protocol Version | 3.0 Password Used | false GSSAPI Authenticated | false Backend PID | 26544 SSL Connection | false Superuser | off Hot Standby | off(12 rows)Expected resultSocket directory rather than host,
Password Used: false,Superuser: off.Success conditionYou can state how you are connected and with what privileges.
Troubleshooting
FATAL: Peer authentication failed for user "x".Why: A role named x exists, but your OS user is not x.
Fix:
psql -U xdoes not help - peer compares the OS user. Eithersudo -u x, or use a TCP connection with a password.A password works over TCP and is refused locally.
Why: The local line uses peer, which ignores passwords entirely.
Fix:Correct behaviour. Add a
local ... scram-sha-256line above the peer line if you genuinely want password auth on the socket.Changes to pg_hba.conf have no effect.
Why: It is read at startup and on reload.
Fix:
sudo systemctl reload postgresql. A reload is enough - no restart needed.