How to install PostgreSQL on Ubuntu 24.04
We earn commissions when you shop through the links below.
The commands we ran on a fresh Ubuntu 24.04, each with what it printed: install, first login, your own user, “Peer authentication failed” with two fixes, the undo.
Short answer: sudo apt update, then
sudo apt install -y postgresql. On 5 October 2026 that gave us PostgreSQL 16.15,
running and listening on this machine only. The first login is
sudo -u postgres psql.
psql -U postgres fails with Peer authentication failed for user "postgres",
and that is the install working as set up: over the local socket PostgreSQL lets you in only as
the database user that has your system user's name. Below: why, two fixes that we ran, a user
and a database of your own, and how to remove everything, down to what the packages leave behind.
What this was run on, and what it does not cover
Every command on this page was run by a script on a fresh virtual machine at a cloud provider, started from Ubuntu's official 24.04 server image. Nothing was installed or changed on it before the first command. Each block marked Output, the block after a command, is what the command above it printed, from the run's log: all of its lines where the output is short, the ones that matter where it is long. A line is shown whole; only the lines of the server's own log are shown without the time and the process number they start with. The machine said this about itself:
date -u +%Y-%m-%d
lsb_release -a
nproc
free -m
2026-10-05
Distributor ID: Ubuntu
Description: Ubuntu 24.04.5 LTS
Release: 24.04
Codename: noble
2
total used free shared buff/cache available
Mem: 3908 457 3265 0 403 3450
One system version, one machine, one day: the PostgreSQL you get is the one Ubuntu's archive
holds on the day you install. Some things differ on a machine of your own. The image's user is
called ubuntu and may use sudo without a password; where a message
below says ubuntu, yours says your own user's name. The script had no terminal:
where a command needs one (psql's prompt, a password, a question), the script ran it under a
pseudo-terminal and typed the answers, and the block shows them as the terminal echoed them.
The script ran every command in a shell of its own; your terminal is one shell for all of them.
And the address of Ubuntu's archive in apt's first lines depends on where your machine stands;
we do not print those lines.
Not covered: reaching the database from another machine (the listen address, the firewall, TLS), backups, and tuning. After this page PostgreSQL answers on this machine only.
1. Install PostgreSQL
sudo apt update
apt-cache policy postgresql
postgresql:
Installed: (none)
Candidate: 16+257build1.1
The candidate is the version Ubuntu's archive will install: the package postgresql
is a pointer to the PostgreSQL that this Ubuntu release ships, here 16.
sudo apt install -y postgresql
Among much else, apt lists what it adds and then creates a database cluster:
The following NEW packages will be installed:
libcommon-sense-perl libjson-perl libjson-xs-perl libllvm17t64 libpq5
libtypes-serialiser-perl postgresql postgresql-16 postgresql-client-16
postgresql-client-common postgresql-common ssl-cert
Creating new PostgreSQL cluster 16/main ...
/usr/lib/postgresql/16/bin/initdb -D /var/lib/postgresql/16/main --auth-local peer --auth-host scram-sha-256 --no-instructions
Keep the second line in mind: --auth-local peer --auth-host scram-sha-256 is where
the error of section 4 comes from. And keep the first block in mind for section 9: these
packages are what an undo has to take away again.
2. Check what you got
psql --version
psql (PostgreSQL) 16.15 (Ubuntu 16.15-0ubuntu0.24.04.1)
The service is enabled and the cluster is online:
systemctl is-enabled postgresql
pg_lsclusters
enabled
Ver Cluster Port Status Owner Data directory Log file
16 main 5432 online postgres /var/lib/postgresql/16/main /var/log/postgresql/postgresql-16-main.log
The state of the unit postgresql.service looks like a fault and is none: it has no
process of its own. The server runs in the unit [email protected]:
systemctl status postgresql --no-pager --lines=0
● postgresql.service - PostgreSQL RDBMS
Loaded: loaded (/usr/lib/systemd/system/postgresql.service; enabled; preset: enabled)
The next line starts with Active: active (exited). And the other unit:
systemctl status postgresql@16-main --no-pager --lines=0
● [email protected] - PostgreSQL Cluster 16-main
Loaded: loaded (/usr/lib/systemd/system/[email protected]; enabled-runtime; preset: enabled)
Its next line starts with Active: active (running). It listens on port 5432 of
this machine only (127.0.0.1), not on the network:
sudo ss -ltnp | grep 5432
LISTEN 0 200 127.0.0.1:5432 0.0.0.0:* users:(("postgres",pid=4085,fd=6))
3. The first login
The install made one database user, postgres, a superuser without a password, and
a system user of the same name, which was not there before. You log in by becoming that system
user for one command. \conninfo says how you are connected, \q leaves:
sudo -u postgres psql
psql (16.15 (Ubuntu 16.15-0ubuntu0.24.04.1))
Type "help" for help.
postgres=# \conninfo
You are connected to database "postgres" as user "postgres" via socket in "/var/run/postgresql" at port "5432".
postgres=# \q
With -c, psql runs one command and ends; the rest of this page uses that form, so
that each step is one line. The users there are, and whether they have a password:
sudo -u postgres psql -c "\du"
List of roles
Role name | Attributes
-----------+------------------------------------------------------------
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS
sudo -u postgres psql -c "SELECT rolname, rolpassword IS NULL AS no_password FROM pg_authid WHERE rolcanlogin;"
rolname | no_password
----------+-------------
postgres | t
(1 row)
4. The error: Peer authentication failed for user "postgres"
Now the command that gives the error:
psql -U postgres
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: Peer authentication failed for user "postgres"
The server's own log says what it compared:
sudo tail -n 4 /var/log/postgresql/postgresql-16-main.log
postgres@postgres LOG: provided user name (postgres) and authenticated user name (ubuntu) do not match
Read it word by word. Provided: the database user you asked for with -U.
Authenticated: the system user you are, which the server gets from the operating system,
not from you. Peer authentication lets you in when the two names are the same, and it works
only for connections on this machine's socket (the manual's section on
peer authentication). Which
method applies is decided by the file pg_hba.conf:
sudo grep -v -e "^#" -e "^$" /etc/postgresql/16/main/pg_hba.conf
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
local replication all peer
host replication all 127.0.0.1/32 scram-sha-256
host replication all ::1/128 scram-sha-256
The lines with replication are for copying the database to another server; a login
meets the others. The server takes the first line that matches the kind of connection, the
database and the user, and tries nothing after it
(the manual on pg_hba.conf).
local is the socket: peer. host is TCP, here only from this machine:
a password, by the method scram-sha-256. So there are two honest ways in. Be the
system user (section 3). Or have a password and come over TCP (section 5) or change one line
for one user (section 6).
Many answers to this error tell you to change peer to trust. We do
not: by the manual, trust lets anyone who can reach the server log in as any
database user, the superuser included, without a password.
5. A user and a database of your own
An application should not log in as the superuser. Make a user with a password, and a database that it owns. Use a password of your own; ours is an example and stands in a public page.
sudo -u postgres psql -c "CREATE ROLE app LOGIN PASSWORD 'example-password-change-me';"
sudo -u postgres createdb --owner=app appdb
CREATE ROLE
On the socket the new user meets the same rule as before, because no system user is called
app:
psql -U app -d appdb
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: Peer authentication failed for user "app"
Fix one: come over TCP. -h localhost makes it a host
connection, and those ask for the password. Nothing in any file changes. The script typed the
password at the prompt; a terminal does not show it:
psql -h localhost -U app -d appdb -c "\conninfo"
Password for user app:
You are connected to database "appdb" as user "app" on host "localhost" (address "127.0.0.1") at port "5432".
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)
From here on the script hands psql the password in the variable PGPASSWORD, so
that a step is one line without a prompt. The user can work in its database:
PGPASSWORD=example-password-change-me psql -h localhost -U app -d appdb -c "CREATE TABLE notes (id integer PRIMARY KEY, body text); INSERT INTO notes VALUES (1, 'hello'); SELECT * FROM notes;"
CREATE TABLE
INSERT 0 1
id | body
----+-------
1 | hello
(1 row)
From the manual, not from our run: both ways of writing a password into a
command line are the script's, not a habit to copy. The manual does not recommend
PGPASSWORD, because some operating systems let other users see a process's
environment variables, and points to a password file instead
(34.15 Environment Variables).
And psql's \password, which section 7 runs, sets a password so that it "does not
appear in cleartext in the command history, the server log, or elsewhere"
(psql in the PostgreSQL 16 manual).
Of a password written after CREATE ROLE … PASSWORD, as above, the manual says that
it "might also be logged in the client's command history or the server log"
(CREATE ROLE, Notes).
6. Fix two: a password on the socket, for this one user
If a program must use the socket as app, give that user a line of its own in
pg_hba.conf, above the line for everyone, because the first match wins.
Keep a copy of the file first. In an editor you would add the one line the diff
below shows; the script did it with sed:
sudo cp /etc/postgresql/16/main/pg_hba.conf /etc/postgresql/16/main/pg_hba.conf.before
sudo sed -i "/^local[[:space:]]\+all[[:space:]]\+all[[:space:]]\+peer/i local all app scram-sha-256" /etc/postgresql/16/main/pg_hba.conf
sudo diff /etc/postgresql/16/main/pg_hba.conf.before /etc/postgresql/16/main/pg_hba.conf || true
122a123
> local all app scram-sha-256
The numbers (122a123 here, and 118, 123 and 124 below) are line numbers of our file; yours may
differ. What counts is that the new line stands above local all all peer. Check
the edit before it is in force: the view pg_hba_file_rules shows the file as it is
now, not what the server has loaded, with an error in its last column for a line the server
could not use
(the manual on the view).
sudo -u postgres psql -c "SELECT line_number, type, database, user_name, address, auth_method, error FROM pg_hba_file_rules;"
line_number | type | database | user_name | address | auth_method | error
-------------+-------+---------------+------------+-----------+---------------+-------
118 | local | {all} | {postgres} | | peer |
123 | local | {all} | {app} | | scram-sha-256 |
124 | local | {all} | {all} | | peer |
The new line is there, above the line for everyone, and its last column is empty. The server does not use it yet: it reads the file when it starts and when it is told to reload, so the login still fails:
PGPASSWORD=example-password-change-me psql -U app -d appdb -c "\conninfo"
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: Peer authentication failed for user "app"
Reload, and the same command works:
sudo systemctl reload postgresql
PGPASSWORD=example-password-change-me psql -U app -d appdb -c "\conninfo"
You are connected to database "appdb" as user "app" via socket in "/var/run/postgresql" at port "5432".
The line names one user, so nothing else moved. We ran both logins of before again after the
reload: the system user still gets in without a password, and psql -U postgres
still fails with the peer error.
sudo -u postgres psql -c "\conninfo"
You are connected to database "postgres" as user "postgres" via socket in "/var/run/postgresql" at port "5432".
7. The other errors of a first day, each with its fix
Each of these was made on purpose in the run, before its fix.
role "ubuntu" does not exist
psql
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: role "ubuntu" does not exist
Without -U, psql asks for the database user with your system user's name, and there
is none. Name a user that exists (-U app), or make one with your name:
sudo -u postgres createuser "$(whoami)"
database "ubuntu" does not exist, database "app" does not exist
The same command again, after the createuser above: the login now works, and the next thing is missing.
psql
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: database "ubuntu" does not exist
PGPASSWORD=example-password-change-me psql -h localhost -U app
psql: error: connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL: database "app" does not exist
Without -d, psql asks for a database named like the user. The login itself worked;
the database is missing. Name the one you mean:
psql -d appdb -c "\conninfo"
You are connected to database "appdb" as user "ubuntu" via socket in "/var/run/postgresql" at port "5432".
The same message comes for a name you mistyped:
sudo -u postgres psql -d shop
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: database "shop" does not exist
sudo -u postgres psql -l lists the databases there are.
password authentication failed for user "app"
psql prints the message twice:
PGPASSWORD=wrong psql -h localhost -U app -d appdb
psql: error: connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL: password authentication failed for user "app"
connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL: password authentication failed for user "app"
The password is wrong. If it is lost, the superuser sets a new one, and the old one stops working: after the change, the first password is refused.
sudo -u postgres psql -c "ALTER ROLE app PASSWORD 'another-example-password';"
PGPASSWORD=example-password-change-me psql -h localhost -U app -d appdb -c "\conninfo"
ALTER ROLE
psql: error: connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL: password authentication failed for user "app"
connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL: password authentication failed for user "app"
That form writes the new password into the command. At a terminal, \password
asks for it instead, twice, and shows nothing of it; the script typed
a-third-example-password:
sudo -u postgres psql -c "\password app"
Enter new password for user "app":
Enter it again:
PGPASSWORD=a-third-example-password psql -h localhost -U app -d appdb -c "\conninfo"
You are connected to database "appdb" as user "app" on host "localhost" (address "127.0.0.1") at port "5432".
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)
From here on the password of app is the last one set,
a-third-example-password.
password authentication failed for user "postgres"
PGPASSWORD=anything psql -h localhost -U postgres
psql: error: connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL: password authentication failed for user "postgres"
connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL: password authentication failed for user "postgres"
Here no password can be right, and only the server's log says why:
sudo tail -n 4 /var/log/postgresql/postgresql-16-main.log
postgres@postgres DETAIL: User "postgres" has no password assigned.
The superuser has no password after the install (section 3), and a user without one always fails a password check (the manual on password authentication). Log in as in section 3, or use a user of your own.
8. If you need a newer PostgreSQL than Ubuntu ships
Ubuntu keeps one PostgreSQL version for the life of a release; for 24.04 that is 16. The
PostgreSQL project has its own package repository with newer versions. We ran this on a second
fresh machine of the same kind, also on 5 October 2026, with the commands of
the project's download page for Ubuntu.
The project's script reads a key press before it writes; among its options is y.
We ran it with -y, and it did not wait.
sudo apt update
sudo apt install -y postgresql-common
grep -n -e getopts -e "read " /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh || true
27:while getopts "c:f:h:ipstv:y" opt ; do
128: read enter
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y
This script will enable the PostgreSQL APT repository on apt.postgresql.org on
your system. The distribution codename used will be noble-pgdg.
sudo apt install -y postgresql-18
psql --version
psql (PostgreSQL) 18.6 (Ubuntu 18.6-1.pgdg24.04+2)
The rules for logging in are the same as with Ubuntu's own package, and so is the error:
sudo grep -v -e "^#" -e "^$" /etc/postgresql/18/main/pg_hba.conf
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
local replication all peer
host replication all 127.0.0.1/32 scram-sha-256
host replication all ::1/128 scram-sha-256
psql -U postgres
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: Peer authentication failed for user "postgres"
We ran this pass only as far as the install and the first error. Everything else on this page was run with version 16 from Ubuntu's archive, not with 18.
9. How to undo it
Read this before you type the second command. apt remove takes the
programs away and keeps your configuration, your databases and the log. apt purge
asks whether to delete them too, and deletes them if you answer yes.
Remove: the programs go, the data stays
sudo apt remove -y postgresql postgresql-16 postgresql-client-16 postgresql-common postgresql-client-common
sudo ls /etc/postgresql/16/main
sudo ls /var/lib/postgresql/16/main
ls /var/log/postgresql
pg_hba.conf
pg_hba.conf.before
pg_ident.conf
postgresql.conf
PG_VERSION
base
global
postgresql-16-main.log
The configuration, the data folder and the log are still there. Nothing listens on port 5432 any more: this printed nothing and ended with an error.
sudo ss -ltnp | grep 5432
Purge: it asks, and "no" keeps your data
Typed at a terminal without -y, the purge asks twice: apt whether to continue, then
the package whether to delete the databases. The script answered y, then
no:
sudo apt purge postgresql postgresql-16 postgresql-client-16 postgresql-common postgresql-client-common
Do you want to continue? [Y/n] y
Removing the PostgreSQL server package will leave existing database clusters
intact, i.e. their configuration, data, and log directories will not be removed.
On purging the package, the directories can optionally be removed.
Remove PostgreSQL directories when package is purged? [yes/no] no
After "no" the three folders held what they held before (the same three ls
commands, the same output). The data is whole: a new install found the cluster, with the
database of section 5 in it.
sudo apt install -y postgresql
sudo -u postgres psql -c "\l appdb"
Name | Owner | Encoding | Locale Provider | Collate | Ctype | ICU Locale | ICU Rules | Access privileges
-------+-------+----------+-----------------+---------+---------+------------+-----------+-------------------
appdb | app | UTF8 | libc | C.UTF-8 | C.UTF-8 | | |
(1 row)
Purge, answered "yes": the databases are deleted
The same command again, answered y, then yes:
sudo apt purge postgresql postgresql-16 postgresql-client-16 postgresql-common postgresql-client-common
Remove PostgreSQL directories when package is purged? [yes/no] yes
Dropping cluster main...
ls -ld /etc/postgresql /var/lib/postgresql /var/log/postgresql 2>&1
ls: cannot access '/var/lib/postgresql': No such file or directory
ls: cannot access '/var/log/postgresql': No such file or directory
drwxr-xr-x 3 postgres postgres 4096 Oct 5 12:47 /etc/postgresql
The data and the log are gone, and nothing asks a second time.
The form that deletes without asking
With DEBIAN_FRONTEND=noninteractive the package is told not to ask, and with
-y apt does not ask either. We installed once more, so that there was a cluster,
and ran it: no question, the cluster dropped. Use this form only where you mean it, in a script
for a machine you are throwing away.
sudo DEBIAN_FRONTEND=noninteractive apt purge -y postgresql postgresql-16 postgresql-client-16 postgresql-common postgresql-client-common
Dropping cluster main...
dpkg: warning: while removing postgresql-common, directory '/etc/postgresql' not empty so not removed
What is still there, and how to remove that too
In /etc/postgresql stays what the packages did not make: here our copy of section 6.
sudo find /etc/postgresql
/etc/postgresql
/etc/postgresql/16
/etc/postgresql/16/main
/etc/postgresql/16/main/pg_hba.conf.before
sudo rm -r /etc/postgresql
sudo apt autoremove -y
apt autoremove removes every package apt holds for no longer needed, not only
PostgreSQL's. On our fresh machine those were packages that had come with it; on a machine with a
history, read its list before you add -y.
The following packages will be REMOVED:
libcommon-sense-perl libjson-perl libjson-xs-perl libllvm17t64 libpq5
libtypes-serialiser-perl ssl-cert
After all that, this was still on the machine. The package ssl-cert was
removed but not purged (state rc); the certificate and the key it made at the
install were there; so were the system user postgres and the groups
postgres and ssl-cert:
dpkg -l | grep "^rc"
sudo ls -l /etc/ssl/certs/ssl-cert-snakeoil.pem /etc/ssl/private/ssl-cert-snakeoil.key
getent passwd postgres
getent group postgres ssl-cert
rc ssl-cert 1.1.2ubuntu1 all simple debconf wrapper for OpenSSL
-rw-r--r-- 1 root root 1135 Oct 5 12:47 /etc/ssl/certs/ssl-cert-snakeoil.pem
-rw-r----- 1 root ssl-cert 1704 Oct 5 12:47 /etc/ssl/private/ssl-cert-snakeoil.key
postgres:x:110:114:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash
postgres:x:114:
ssl-cert:x:113:postgres
The script looked for the user, the two groups and the package before its first
apt command and found none; the certificate and the key carry the minute of the
install. On a machine where something else uses ssl-cert or a user
called postgres, leave them. On ours, these commands took them away:
sudo apt purge -y ssl-cert
sudo deluser postgres
sudo delgroup ssl-cert
info: Removing user `postgres' ...
info: Removing group `ssl-cert' ...
After them the same looks found nothing: no package in the state rc, neither
file, no user and no group.
What this database can carry
The install is the easy part. What one PostgreSQL carries, we measured on real machines: how many requests per second one Postgres handles, how big its connection pool should be, and how many users a $12 server with Nginx, Node.js and Postgres carries.
The playground is invite-only during the private preview: join the waitlist to get an invite.
Sources
- Our own run: a script on two fresh Ubuntu 24.04 machines on 5 October 2026. Every command and every output on this page is from the script and its log; the one paragraph marked as being from the manual is the manual's.
- The PostgreSQL project, Linux downloads (Ubuntu): Ubuntu ships one PostgreSQL version per release; the project's Apt repository and its commands.
- PostgreSQL 16 manual, 21.1
The pg_hba.conf File: the first matching line is used and no other;
localandhost;trust; the file is read at start and at a reload. And 54.9 pg_hba_file_rules: the view shows the file as it is, with an error for a line that could not be used. - PostgreSQL 16 manual, 21.9 Peer Authentication and 21.5 Password Authentication.
- PostgreSQL 16 manual, psql:
-c,\q,\password, the default user and database names; 34.15 Environment Variables:PGPASSWORD; and CREATE ROLE, Notes: a password written in the command. - Ubuntu Server documentation,
Install and
configure PostgreSQL: on Ubuntu,
peeris the default for local connections andscram-sha-256for host connections.