BeginnerReferenceDatabases

PostgreSQL 17 Installation and Configuration

Installing PostgreSQL 17 on Ubuntu/Debian, RHEL/Rocky/AlmaLinux, Windows and macOS, with the postgresql.conf and pg_hba.conf settings to review before anything connects to it.

Applies to
PostgreSQL17Released 26 September 2024. Noted where behaviour differs from 16.
Updated Reviewed

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 psql and the rest
  • Data directory: defaults to C:\Program Files\PostgreSQL\17\data
  • Superuser password: set for the postgres database 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-server can pull a module-provided package or fail on a conflict if the distribution’s own postgresql module was never disabled. Detect it by checking dnf module list postgresql before 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 no postgresql module 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-17 fails silently into a non-running state if postgresql-17-setup initdb was skipped; check systemctl status postgresql-17 and 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_addresses still defaults to local connections only, and pg_hba.conf still has to have a matching host line for the connecting address. A closed firewall and a default listen_addresses produce 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.conf matches the connecting address, database, and user combination. Add a host line 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
ReleaseLatestReleasedEnd of lifeStatus
1818.6Sept 2025Nov 2030Supported
1717.11Sept 2024Nov 2029Supported
1616.15Sept 2023Nov 2028Supported
1515.19Oct 2022Nov 2027Supported
1414.24Sept 2021Nov 2026Supported
1313.23Sept 2020Nov 2025End of life
1212.22Oct 2019Nov 2024End of life
1111.22Oct 2018Nov 2023End 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.

Depends on

Must be present for this to run

Deployed with

Commonly run alongside

Alternatives

Solves a similar problem differently