Linux: Ubuntu and Debian
Ubuntu and Debian both ship PostgreSQL in their default repositories, but the version tracks the OS release, not the PostgreSQL release. It is very likely not 17. Installing a specific supported version deliberately means using the PGDG (PostgreSQL Global Development Group) apt repository instead.
Step-by-step
1. Install prerequisites and add the PGDG signing key.
sudo apt install curl ca-certificates
sudo install -d /usr/share/postgresql-common/pgdg
sudo curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc --fail \
https://www.postgresql.org/media/keys/ACCC4CF8.asc
2. Add the repository. Create /etc/apt/sources.list.d/pgdg.sources (replace noble with your
distribution’s codename: jammy for Ubuntu 22.04, bookworm for Debian 12):
Types: deb deb-src
URIs: https://apt.postgresql.org/pub/repos/apt
Suites: noble-pgdg
Architectures: amd64
Components: main
Signed-By: /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc
This is the working apt repository definition. Once this file exists and apt update has run,
apt-cache policy postgresql-17 should show the PGDG source as a candidate.
3. Install PostgreSQL 17.
sudo apt update
sudo apt install postgresql-17
4. Confirm the service started. Unlike the RHEL family package below, this one starts automatically on install.
systemctl status postgresql
pg_lsclusters
pg_lsclusters lists every PostgreSQL cluster on the machine: version, cluster name (main by
default), port, status, and data directory. That matters because Debian and Ubuntu’s packaging
supports multiple PostgreSQL versions and clusters installed side by side, unlike a single-instance
install elsewhere.
Installed binaries: /usr/lib/postgresql/17/bin/ (psql, pg_dump, and the rest). Unlike the
RHEL family and Windows, nothing needs to be added to PATH. Debian and Ubuntu install /usr/bin/psql
as a symlink to pg_wrapper, which resolves to the correct versioned binary automatically, including
when more than one PostgreSQL version is installed side by side.
Default data directory: /var/lib/postgresql/17/main
Default port: 5432
5. Connect.
sudo -u postgres psql
Linux: RHEL, Rocky Linux, and AlmaLinux
What the RHEL family gives you by default is easy to get wrong, and the answer is not 16. On RHEL 9,
dnf install postgresql-server installs PostgreSQL 13, the initial Application Stream version, and
Red Hat defines no default module stream at all: 15, 16 and 18 each have to be selected explicitly.
On RHEL 10 the same command installs 16, and 18 arrived as postgresql18-server. Red Hat skipped 17
in both, so running it means the PGDG yum repository, and on RHEL 9 disabling the distribution’s own
PostgreSQL module first so the two do not conflict. RHEL 10 dropped modules in favour of versioned
package names, so the disable step below does not apply there. (dnf is the command on current RHEL family releases; yum is a symlink to it and
works identically if you are on an older system that still calls it that.)
Step-by-step
1. Install the EPEL repository. The PGDG yum repository depends on EPEL for some packages; this is a real prerequisite the PGDG repository RPM does not pull in for you.
sudo dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
Use epel-release-latest-8.noarch.rpm for RHEL 8 and derivatives.
2. Add the PGDG repository. This one command both installs and configures a working yum
repository: it writes /etc/yum.repos.d/pgdg-redhat-all.repo, covering every supported PostgreSQL
version as separate, individually enablable repo entries.
sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm
Use EL-8-x86_64 in place of EL-9-x86_64 for RHEL 8 and derivatives. Confirm the repository is
active:
dnf repolist | grep pgdg
3. Disable the built-in PostgreSQL module.
sudo dnf -qy module disable postgresql
Without this, dnf install postgresql17-server can pull the module-provided package instead of the
PGDG one, or fail with a conflict.
4. Install PostgreSQL 17.
sudo dnf install -y postgresql17-server
5. Initialise the data directory and start the service. Unlike the Debian/Ubuntu package, this one does not do either automatically. Both commands below are required, not optional verification steps.
sudo /usr/pgsql-17/bin/postgresql-17-setup initdb
sudo systemctl enable postgresql-17
sudo systemctl start postgresql-17
Installed binaries: /usr/pgsql-17/bin/ (psql, pg_dump, and the rest). Not on PATH by
default: use the full path, or add /usr/pgsql-17/bin to PATH yourself.
Default data directory: /var/lib/pgsql/17/data
Default port: 5432
Both Linux distributions: configuration files to review first
postgresql.conf
Location: /etc/postgresql/17/main/postgresql.conf on Debian/Ubuntu,
/var/lib/pgsql/17/data/postgresql.conf on RHEL family (RHEL keeps configuration inside the data
directory; Debian/Ubuntu splits it out under /etc).
Three settings to review before anything else, with their documented defaults:
| Setting | Default | What it controls |
|---|---|---|
listen_addresses |
localhost |
Which network interfaces accept TCP/IP connections. The default accepts only local loopback connections - a fresh install is not reachable from another machine until this changes. |
max_connections |
100 (may be lower if the kernel will not support it) | The hard ceiling on concurrent connections. PostgreSQL forks a process per connection, so this is a memory sizing decision, not just a limit. |
shared_buffers |
128MB (may be less if the kernel will not support it) | Memory reserved for the server’s shared buffer cache. The documentation’s own starting recommendation for a dedicated server with 1GB or more of RAM is roughly 25% of system memory - the packaged default is a safe minimum, not a production setting. |
To accept remote connections, set listen_addresses = '*' (all interfaces) or a specific address, and
restart the server. This parameter can only be changed at server start, not reloaded.
pg_hba.conf
Same directory as postgresql.conf on each platform. This file, not postgresql.conf, is what
actually decides whether a given connection attempt is authenticated at all: each line matches a
connection type, source address, database, and user against an authentication method, checked in
order, first match wins. listen_addresses controls which network interfaces the server listens on;
pg_hba.conf controls who is permitted to authenticate once a connection reaches it. Both have to
allow a connection for it to succeed.
The file installed by initdb typically allows local Unix-socket connections without a password
(useful for the sudo -u postgres psql pattern above) and restricts TCP connections to localhost
only, matching the listen_addresses default. To allow a specific remote host to connect, add a
host line naming the database, user, source address, and authentication method. scram-sha-256 is
the documented recommended password method:
host all all 203.0.113.10/32 scram-sha-256
An authentication-only change needs a reload, not a restart: pg_hba.conf is re-read on SIGHUP,
unlike listen_addresses:
sudo -u postgres psql -c "SELECT pg_reload_conf();"
# or, without connecting first:
sudo pg_ctl reload -D /var/lib/pgsql/17/data # RHEL family path shown; adjust for Debian/Ubuntu
Firewall
Open port 5432 for whichever hosts need to reach it. Do not open it to the world by default.
# Ubuntu/Debian (ufw)
sudo ufw allow from 203.0.113.0/24 to any port 5432
# RHEL family (firewalld)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.0/24" port protocol="tcp" port="5432" accept'
sudo firewall-cmd --reload
Post-install verification
psql --version
sudo -u postgres psql -c "SELECT version();"
Windows
PostgreSQL’s Windows distribution is the EDB interactive installer, hosted by EDB and not on postgresql.org’s own servers, bundling the server, pgAdmin, and StackBuilder (an add-on package manager). PostgreSQL 17 is tested by EDB against Windows Server 2022 and 2019; desktop Windows releases of comparable vintage are expected to work but are not the platforms EDB tests against.
Step-by-step
1. Download. The direct link for the current PostgreSQL 17 64-bit Windows installer, from EDB’s own download host, is:
https://get.enterprisedb.com/postgresql/postgresql-17.11-1-windows-x64.exe
This is the same file the interactive selector at postgresql.org/download/windows resolves to. EDB
publishes a new build under a new filename for each minor release, so this exact URL will eventually
point at an outdated version. If 17.11 is no longer current, get the current one from
postgresql.org/download/windows instead of guessing the next filename.
2. Run the installer and step through the wizard. In order, it asks for:
- Installation directory: defaults to
C:\Program Files\PostgreSQL\17 - Components: PostgreSQL Server, pgAdmin 4, Stack Builder, and Command Line Tools are all
selected by default; leave Command Line Tools checked, it is what installs
psqland the rest - Data directory: defaults to
C:\Program Files\PostgreSQL\17\data - Superuser password: set for the
postgresdatabase role and the Windows service account during install, not afterward - Port: defaults to 5432
- Locale: affects collation and sort order for the cluster; changing it after data exists requires a full reinitialisation, not a configuration change
3. Finish, and skip Stack Builder unless you need one of the add-ons it offers (PostGIS, drivers, replication tools). It is optional and unrelated to whether the server itself is installed correctly.
Service
The installer registers a Windows service, postgresql-x64-17 by default. Manage it from the
Services console (services.msc) or from an elevated command prompt:
net start postgresql-x64-17
net stop postgresql-x64-17
Installed binaries: C:\Program Files\PostgreSQL\17\bin\ (psql, pg_dump, and the rest).
Default data directory: C:\Program Files\PostgreSQL\17\data
Default port: 5432
Add psql to PATH
The installer does not always add the bin directory to PATH automatically. Add it if psql is
not found in a new terminal:
setx PATH "%PATH%;C:\Program Files\PostgreSQL\17\bin"
Open a new terminal after running this - setx does not affect the current session.
Connect and verify
psql -U postgres
Inside psql:
\conninfo
SELECT version();
postgresql.conf and pg_hba.conf live inside the data directory (C:\Program Files\PostgreSQL\17\data by default) on Windows, the same as the RHEL family layout. There is no
separate /etc-style split as on Debian/Ubuntu. The same three postgresql.conf settings and the
same pg_hba.conf authentication logic described above apply unchanged; only the file paths and the
reload command differ:
pg_ctl reload -D "C:\Program Files\PostgreSQL\17\data"
macOS
macOS has no single blessed route. postgresql.org lists five, and the two worth considering are Homebrew, if you already manage packages that way, and Postgres.app, if you want a server you can switch off from the menu bar. Both install the same PostgreSQL; they differ in where it puts things and in what happens when you are not looking.
One decision they share, and it is the source of most macOS confusion: there is no postgres
superuser. initdb names the bootstrap superuser after the operating-system user that ran it
unless told otherwise, and on macOS nothing tells it otherwise. Your superuser is your own login
name. Every “role does not exist” error below traces back to that one line of behaviour.
Note also that the EDB installer, the route the Windows section uses, is tested by EDB against macOS 11.x on Intel and 12.x on Apple Silicon for PostgreSQL 17. It is expected to work on newer releases but those are not the versions EDB tests.
Homebrew, step-by-step
1. Install the versioned formula. Ask for the major version explicitly. postgresql alone
tracks whatever Homebrew considers current, which will move under you at some point.
brew install postgresql@17
2. Put the binaries on PATH. Versioned PostgreSQL formulae are keg-only, meaning Homebrew
deliberately does not symlink them into the main prefix, so nothing works until you say where they
are. Use the prefix for your architecture: /opt/homebrew on Apple Silicon, /usr/local on Intel.
# Apple Silicon
echo 'export PATH="/opt/homebrew/opt/postgresql@17/bin:$PATH"' >> ~/.zprofile
# Intel
echo 'export PATH="/usr/local/opt/postgresql@17/bin:$PATH"' >> ~/.zprofile
exec $SHELL -l
3. Start the server. brew services start registers a launchd agent. Brew describes it as
starting the service now and restarting it at login, and login is the accurate word: the server
comes back when you log in, not while the machine sits at the login window.
brew services start postgresql@17
brew services list
For this session only, with no launchd registration, use brew services run postgresql@17, which
runs the service without registering it to launch at login.
4. Connect. The formula creates a cluster during install, so there is nothing to initialise.
psql postgres
The database name is not optional here. psql with no argument looks for a database matching your
user name, and the formula never creates one: its install step runs initdb and stops, and initdb
creates exactly three databases, postgres, template1 and template0. So bare psql fails on a
fresh Homebrew install while psql postgres works.
Installed binaries: $HOMEBREW_PREFIX/opt/postgresql@17/bin
Data directory: $HOMEBREW_PREFIX/var/postgresql@17
Server log: $HOMEBREW_PREFIX/var/log/postgresql@17.log
Default port: 5432
The cluster the formula builds is created with initdb --locale=en_US.UTF-8 -E UTF-8, so the locale
is fixed at install time regardless of your system settings. Changing it later means a new cluster,
not a configuration change.
Postgres.app, step-by-step
1. Download and open it. Drag it to /Applications, open it, and press Initialize. There is no
installer and no launchd job: the server runs while the app runs and stops when it quits, which is
the reason to choose it on a laptop.
2. Put the command-line tools on PATH. The app bundles them inside itself, so a shell knows
nothing about them until told.
sudo mkdir -p /etc/paths.d && echo /Applications/Postgres.app/Contents/Versions/latest/bin | sudo tee /etc/paths.d/postgresapp
Open a new terminal window afterwards, then confirm with which psql.
That command works through path_helper, the macOS utility that builds PATH from /etc/paths and
/etc/paths.d. It appends, so this directory lands after /usr/local/bin and after
/opt/homebrew/bin. If a Homebrew PostgreSQL is also installed, its psql wins, and a .zprofile
line like the one in the Homebrew section wins by a wider margin still, because that prepends. When
both routes are present, which psql is the only reliable answer to which one you are about to
talk to.
3. Connect.
psql
Installed binaries: /Applications/Postgres.app/Contents/Versions/latest/bin
Data directory: inside ~/Library/Application Support/Postgres, in a folder named var- plus the major version, so var-17 for this one
Server log: postgres-server.log, inside the data directory
Default port: 5432
Connecting: which user you are, and how to reach the rest
The two routes leave you with different sets of roles, which is why advice copied from a Linux tutorial so often fails here. Establish what actually exists before trying to connect as anything.
| Homebrew | Postgres.app | |
|---|---|---|
| Bootstrap superuser | Your macOS login name | postgres |
| Also created | Nothing else | A superuser and a database, both named after your login |
| Databases present | postgres, template1, template0 |
Those three, plus one named after your login |
Is there a postgres role? |
No | Yes |
What bare psql does |
Fails: no database matches your name | Opens your own database |
Homebrew has no postgres role because its install step runs initdb without -U, and initdb
names the bootstrap superuser after whoever ran it. Postgres.app initialises with -U postgres and
then adds a superuser matching your login on top, so it has both.
Find out where you stand. Connect to the one database that exists on every installation, then ask:
psql postgres
\conninfo -- which user, which database, which port, which socket
\du -- every role, and which are superusers
\l -- every database
\conninfo is the one to reach for when an error makes no sense. It answers “who am I connected as”
without guessing.
Connecting as postgres specifically. On Postgres.app the role is there, so name it:
psql -U postgres -d postgres
On Homebrew that command fails, because the role does not exist. If you want it, for parity with a Linux box or because a tool expects it, create it from the superuser you already have:
createuser -s postgres
psql -U postgres -d postgres
Note the difference from Linux, where postgres is an operating-system account and you reach the
role through sudo -u postgres psql. On macOS there is no such account under either route. You
connect as a database role from your own shell, and sudo plays no part.
Connecting to a specific database. Two spellings, the second being the one to prefer in scripts because every part is explicit:
psql mydb
psql -h localhost -p 5432 -U "$USER" -d mydb
Once inside, \c otherdb switches database without leaving psql, and \c otherdb otheruser
switches both at once.
Creating something to connect to. A fresh cluster has no application database. Give yourself one
rather than working in postgres, which exists for maintenance and for exactly the case where you
have nowhere else to go:
createdb mydb
psql -d mydb -c "SELECT current_user, current_database();"
For a database owned by a role that is not a superuser, which is the arrangement an application should use, the “After install” section below covers creating the role and handing it ownership.
Configuration on macOS
postgresql.conf and pg_hba.conf live inside the data directory, as they do on the RHEL family
and on Windows, so for Homebrew that is $HOMEBREW_PREFIX/var/postgresql@17 and for Postgres.app
the var-17 directory above. The three settings to review first and the authentication logic are
the same as the Linux sections; only the paths change.
One default is worth knowing before this machine is ever on an untrusted network. initdb uses
trust as its default local authentication method, described in the documentation as being that way
for ease of installation, with an explicit warning not to use it unless you trust every local user.
On a single-user laptop that is defensible. It stops being defensible the moment listen_addresses
is widened, and neither Homebrew nor Postgres.app will mention it at that point.
Reload after editing, rather than restarting:
# Homebrew
pg_ctl reload -D "$(brew --prefix)/var/postgresql@17"
# Postgres.app
pg_ctl reload -D ~/Library/Application\ Support/Postgres/var-17
Troubleshooting
psql: FATAL: role "<your name>" does not exist. The cluster was initialised by a different
user than the one you are now, so the superuser named after that other account is the only one
there. Create yours from the account that does exist:
createuser -U postgres -s $USER
psql: FATAL: database "<your name>" does not exist. psql with no argument opens a database
matching your user name, and that database is missing or was never created. Either make it, or point
psql at the one that always exists:
createdb $USER # or
psql postgres
Port 5432 is already in use. Something is already serving on it, and on macOS that is usually
a second PostgreSQL you forgot about: a Homebrew formula and Postgres.app both running, or an old
EDB install still registered. Find out what holds the port before killing anything:
lsof -nP -iTCP:5432 -sTCP:LISTEN
brew services list
Two servers can coexist happily on different ports. Only one can have 5432.
The server will not start, and nothing explains why. Read the log rather than guessing. For
Homebrew it is $HOMEBREW_PREFIX/var/log/postgresql@17.log; for Postgres.app,
postgres-server.log in the data directory. If the log itself is unhelpful, start the server in the
foreground and let it print to the terminal:
LC_ALL="en_US.UTF-8" "$(brew --prefix)/opt/postgresql@17/bin/postgres" -D "$(brew --prefix)/var/postgresql@17"
The LC_ALL is not decoration. That is the invocation brew info postgresql@17 prints for running
the server without a background service, and the locale is set because the cluster was initialised
under it.
could not translate host name "localhost", or a failure to create a listen socket. These are
not PostgreSQL faults. Both come from /etc/hosts missing its localhost entry or having it
malformed, which happens after hand-editing that file. It should contain 127.0.0.1 localhost and
::1 localhost.
A stale postmaster.pid. PostgreSQL records the server process id in postmaster.pid in the
data directory, and a crash can leave one behind pointing at a process that no longer exists, which
blocks the next start. Postgres.app tries to clear these itself and reports when it cannot. Deleting
the file by hand is the fix, once you have confirmed no postgres process is genuinely running.
command not found: psql. Neither route puts the binaries on PATH for you: Homebrew because
versioned formulae are keg-only, Postgres.app because they live inside the application bundle. Step
2 of the relevant section above is the fix, and a new terminal window is required afterwards for
either. macOS ships no psql of its own, so there is nothing to fall back to and nothing to
accidentally shadow.
psql runs, but connects to the wrong server, or reports a version you did not install. You
have two PostgreSQL installations and are reaching the one earlier in PATH. Ask which binary you
are running and what it is, rather than assuming:
which -a psql
psql --version
psql -c "SHOW data_directory;" postgres
The third command is the one that settles it, because it reports where the running server keeps its data, which identifies the installation rather than the client.
Reinstalling did not give you a clean slate. Homebrew warns about this in the formula’s own caveats: uninstalling a versioned PostgreSQL leaves dead symlinks behind. Clear them before reinstalling, or the new install inherits them.
brew cleanup --prune-prefix
Note also where the data sits relative to what gets removed. The formula itself installs under
$HOMEBREW_PREFIX/Cellar/postgresql@17, while the cluster lives at
$HOMEBREW_PREFIX/var/postgresql@17, a separate tree. Removing the formula therefore does not
remove the databases, which is usually what you want and is occasionally the reason a reinstall
comes back with data you thought had gone.
A major-version upgrade left the cluster unusable. Data directories are not compatible across
major versions, so installing postgresql@18 beside postgresql@17 migrates nothing: you get a
second cluster, and the old one stays where it was. Moving between them is either
pg_upgrade or a dump and restore. Take a
pg_dumpall before either, because a migration that fails halfway can leave a directory that starts
under neither version, and the dump is the only thing that makes that recoverable.
After install, on any platform
Set a strong superuser password if it was not set during install (Linux package installs do not prompt for one the way the Windows installer does):
ALTER USER postgres WITH PASSWORD 'a-strong-password-here';
Create a working database and a non-superuser role. Running everything as postgres is the
starting point every install ships with, not a configuration to keep:
CREATE ROLE app_user WITH LOGIN PASSWORD 'a-different-strong-password';
CREATE DATABASE app_db OWNER app_user;
Apply configuration changes without restarting where possible. Most pg_hba.conf changes and a
subset of postgresql.conf settings take effect on reload; settings marked “can only be set at
server start” in the documentation (listen_addresses, max_connections, and shared_buffers among
them) need a full restart, not a reload.
Load a sample database
An empty database is not enough to tell whether the install actually works end to end: connecting, running a real query, and seeing correct results. Two options, in order of how much they depend on anything outside the install itself.
pgbench: built in, zero download
pgbench ships with the server itself, so this works on every platform above with no extra
download and no version-compatibility question. Whatever pgbench binary is on the machine matches
the server it was installed alongside.
createdb bench
pgbench -i bench
-i creates four tables (pgbench_accounts, pgbench_branches, pgbench_tellers,
pgbench_history) and loads them with generated rows, scaled by -s (default scale factor 1 is
100,000 rows in pgbench_accounts). It is a synthetic banking-style schema built for load testing,
not for learning to query, but it proves the server, createdb, and data loading all work:
psql bench -c "SELECT count(*) FROM pgbench_accounts;"
pgbench bench # runs the default TPC-B-like benchmark against it
Pagila: a realistic relational schema, from source
For a schema worth actually querying, Pagila is the PostgreSQL port of MySQL’s Sakila sample database that the PostgreSQL wiki’s own Sample Databases page recommends: a DVD rental business with films, customers, rentals, and payments, normalised across 15-odd tables, small enough to load in seconds and large enough that joins and aggregates return interesting results.
git clone https://github.com/devrimgunduz/pagila.git
cd pagila
createdb pagila
psql pagila -f pagila-schema.sql
psql pagila -f pagila-data.sql
psql pagila -c "SELECT title, rental_rate FROM film ORDER BY rental_rate DESC LIMIT 5;"
The repository’s own README states it is tested against PostgreSQL 18 and above, so treat that as the
supported target, not an assumption this page can settle. If pagila-schema.sql fails to
load against 17, that mismatch is the reason to check first. The features that the README explicitly
ties to a specific version, uuidv7() (18 only) and the JSON_TABLE()/SQL-JSON functions (17 or
later) demonstrated in its own examples, are separate from the base schema and data load above, and
are not needed to get a working, queryable sample database on 17.
The trade-off: PGDG repository versus the distribution’s own package
Installing from the PGDG repository, as this page describes, gets you the specific PostgreSQL version you asked for and the project’s own update cadence, independent of the OS release cycle. The cost is that the distribution vendor did not test that exact combination the way it tested whatever version it ships itself. Red Hat’s own PostgreSQL packages went through Red Hat’s qualification process, and PGDG’s 17 package did not go through that same process for RHEL 9 specifically, though PGDG maintains it for exactly this use. Note also that Red Hat’s newest stream is 18, not 17, so the choice on a current RHEL is between a vendor-qualified 18 and a PGDG 17. For most teams that need a current, supported PostgreSQL version instead of whatever a multi-year-old OS release happened to ship, PGDG is the right trade to make. Just be aware it is a trade, not a strictly-better option with no downside.
Failure modes
- RHEL 9: forgetting to disable the built-in module before installing.
dnf install postgresql17-servercan pull a module-provided package or fail on a conflict if the distribution’s ownpostgresqlmodule was never disabled. Detect it by checkingdnf module list postgresqlbefore installing; the fix is running the disable command in the RHEL section above before installing, not after. This one does not apply to RHEL 10, which distributes these packages as versioned RPMs and has nopostgresqlmodule to disable. - RHEL family: server does not start because initdb was never run. Unlike the Debian/Ubuntu
package, RHEL family packages do not initialise the data directory automatically.
systemctl start postgresql-17fails silently into a non-running state ifpostgresql-17-setup initdbwas skipped; checksystemctl status postgresql-17and the log directory under the data directory for the actual error. - Remote connections refused after opening the firewall. Opening port 5432 is necessary but not
sufficient.
listen_addressesstill defaults to local connections only, andpg_hba.confstill has to have a matchinghostline for the connecting address. A closed firewall and a defaultlisten_addressesproduce the same symptom (connection refused or timeout) from the client’s point of view, so check both instead of assuming which one is misconfigured. - “no pg_hba.conf entry for host” after opening the firewall and listen_addresses. This means the
network path works but no line in
pg_hba.confmatches the connecting address, database, and user combination. Add ahostline for it and reload, without widening an existing line’s scope more than the connection actually needs. - Windows: locale chosen at install time turns out to be wrong. Locale affects collation and sort order for the entire cluster. Changing it after any data exists requires reinitialising the cluster, not a configuration change. Worth getting right during the interactive install, not discovering the mismatch later.
Diagnostics
After installation, common issues and how to resolve them.
Service fails to start. Check the PostgreSQL log (usually /var/log/postgresql/ on Debian or
/var/lib/pgsql/<version>/data/log/ on RHEL):
sudo journalctl -u postgresql@17-main --no-pager --since "5 minutes ago"
Common causes: port 5432 already in use (another instance or stale lock file), data directory
permissions wrong (must be owned by postgres with mode 0700), or shared_buffers set too high
for available shared memory (kernel shmmax too low).
Cannot connect: “connection refused”. Check listen_addresses in postgresql.conf:
sudo grep listen_addresses /etc/postgresql/17/main/postgresql.conf
# Should be '*' or the specific interface, not just 'localhost'
Also check pg_hba.conf for a matching host entry. A missing entry produces
no pg_hba.conf entry for host in the client error, not connection refused. If you get
connection refused, PostgreSQL is either not running or not listening on that address/port.
Locale errors during initdb. On minimal container images, locale data may be missing:
locale -a | grep en_US
# If empty:
sudo locale-gen en_US.UTF-8
sudo dpkg-reconfigure locales
pgbench fails with “relation pgbench_accounts does not exist”. You must initialise the test schema first:
pgbench -i -s 10 testdb
# Then run the benchmark:
pgbench -c 10 -j 2 -T 60 testdb
Extension installation fails. Most extensions require the -dev or -devel package:
# Debian/Ubuntu:
sudo apt install postgresql-17-pgvector
# RHEL:
sudo dnf install pgvector_17
Then in SQL: CREATE EXTENSION vector;. If it fails with “could not open extension control file”,
the package is not installed for the correct PostgreSQL major version.
WAL directory filling the disk. After installation with replication configured but no standby connected, WAL files accumulate. Check:
SELECT slot_name, active, restart_lsn FROM pg_replication_slots;
An inactive replication slot prevents WAL cleanup. Drop unused slots:
SELECT pg_drop_replication_slot('slot_name');
Out of scope
Building from source, container or Docker deployment, and cloud-managed PostgreSQL (RDS, Cloud SQL, Azure Database) are each a different operational model with their own defaults and failure modes, not a variation on a from-scratch install. Each would need its own page, not a section here. Versions before 16 are out of support scope for this page; see the version matrix below for what is still supported.
PostgreSQL release support
5 supported| Release | Latest | Released | End of life | Status |
|---|---|---|---|---|
18 | 18.6 | Sept 2025 | Nov 2030 | Supported |
17 | 17.11 | Sept 2024 | Nov 2029 | Supported |
16 | 16.15 | Sept 2023 | Nov 2028 | Supported |
15 | 15.19 | Oct 2022 | Nov 2027 | Supported |
14 | 14.24 | Sept 2021 | Nov 2026 | Supported |
13 | 13.23 | Sept 2020 | Nov 2025 | End of life |
12 | 12.22 | Oct 2019 | Nov 2024 | End of life |
11 | 11.22 | Oct 2018 | Nov 2023 | End of life |
Data as of 2026-10-01 from endoflife.date. Refresh with node scripts/fetch-versions.mjs.
Where PostgreSQL sits
How this component relates to the rest of the stack. Items without a link are not covered here yet.