Short answer: pg_ctl -D /path/to/data reload, or from inside psql,
SELECT pg_reload_conf();. Both re-read postgresql.conf and
pg_hba.conf without dropping a single connection. Settings whose context is
postmaster — shared_buffers, max_connections,
wal_level — will not apply, and PostgreSQL will not warn you. Check
pg_settings.pending_restart to find out.
Table of Contents
The -D is not optional
Most guides (this one included, until today) show pg_ctl reload with no data
directory. It fails:
$ pg_ctl reload
pg_ctl: no database directory specified and environment variable PGDATA unset
Try "pg_ctl --help" for more information.
$ echo $?
1It only works if PGDATA happens to be exported in that shell — which it is for the
postgres system user on most packaged installs, and is not when you su into
a bare shell or run it from a script. Pass -D explicitly and it always works:
$ pg_ctl -D /opt/homebrew/var/postgresql@17 reload
server signaled
$ echo $?
0Don’t know your data directory? Ask the server:
SHOW data_directory;
SHOW config_file;
SHOW hba_file;Proof that a reload actually applies a setting
work_mem has context user, so it takes effect on reload:
postgres=# SHOW work_mem;
work_mem
----------
4MB
$ echo "work_mem = '8MB'" >> $PGDATA/postgresql.conf
$ pg_ctl -D $PGDATA reload
server signaled
postgres=# SHOW work_mem;
work_mem
----------
8MBAnd proof that some settings silently don’t
This is the part that costs people an afternoon. shared_buffers has context
postmaster. Reload it and nothing happens — no error, no warning, no log entry:
postgres=# SHOW shared_buffers;
shared_buffers
----------------
128MB
$ echo "shared_buffers = '256MB'" >> $PGDATA/postgresql.conf
$ pg_ctl -D $PGDATA reload
server signaled
postgres=# SHOW shared_buffers;
shared_buffers
----------------
128MB <-- unchangedThe server does record it, but only if you look:
postgres=# SELECT name, setting, pending_restart FROM pg_settings WHERE pending_restart;
name | setting | pending_restart
----------------+---------+-----------------
shared_buffers | 16384 | t
(1 row)Make this your habit: after every reload, run that query. If it returns rows, your
change is sitting in the config file doing nothing until the next restart.
Which settings need a restart?
There are 65 of them in PostgreSQL 17.10. Don’t memorise the list — query it.
context = 'postmaster' means restart required:
SELECT name, context, short_desc
FROM pg_settings
WHERE context = 'postmaster'
ORDER BY name;The other contexts you’ll meet: sighup (applies on reload),
superuser and user (settable per-session), backend (fixed when
a connection starts), and internal (compile-time, not changeable at all).
The three ways to reload, and when each is right
| Method | Command | Use when |
|---|---|---|
pg_ctl | pg_ctl -D $PGDATA reload | You have shell access as the postgres user. Works on any install. |
| SQL | SELECT pg_reload_conf(); | You’re already in psql, or you only have SQL access (managed/cloud PG). Returns t on success. |
| systemd | sudo systemctl reload postgresql@17-main | Packaged Linux installs. Note the versioned unit name — plain postgresql is a wrapper and may not forward the reload. |
Checking the logs
The log path is not /var/log/postgresql/postgresql.log on most systems. Find yours:
SHOW log_directory;
SHOW log_filename;Debian/Ubuntu packages write to /var/log/postgresql/postgresql-17-main.log; Homebrew
writes wherever you pointed -l at start time; RHEL-family defaults to
$PGDATA/log/. A successful reload logs
received SIGHUP, reloading configuration files.
Verified 2026-08-09 on PostgreSQL 17.10 (Homebrew), aarch64-apple-darwin25.6.0.
Every command above was executed on a scratch cluster and the output pasted unedited — including the
failure in the first example. You can reproduce all of it in about 30 seconds with
this script, which creates a throwaway cluster on
port 55432 and tears it down afterwards.
