Stackrig

Home Blog

tested run on a fresh Ubuntu 24.04, 5 October 2026 published

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; local and host; 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, peer is the default for local connections and scram-sha-256 for host connections.

Stackrig