How-To Reload PostgreSQL Config Without Restarting (pg_ctl)

Updated

PostgreSQL elephant logo

To reload PostgreSQL’s configuration without a restart, run pg_ctl -D /path/to/data reload as the OS user that owns the data directory, or run SELECT pg_reload_conf(); as a superuser in psql. systemctl reload postgresql on Debian and Ubuntu, or kill -HUP on the postmaster, does the same thing. Each makes the postmaster re-read postgresql.conf, postgresql.auto.conf, pg_hba.conf and pg_ident.conf and pass the signal to all running server processes, so no connection is dropped. Settings that can only be set at server start, such as shared_buffers, max_connections and wal_level, keep their old value until you restart; pg_settings.pending_restart and the server log show which ones were skipped.

This applies to PostgreSQL 14 through 18, the supported releases as of October 2026 (19 is in beta; 14 reaches end of life on November 12, 2026). I ran the pg_ctl, SQL and kill commands on PostgreSQL 17.11 on macOS and checked them against the 18 documentation. I did not run the Debian and Ubuntu steps; they come from the postgresql-common unit files and documentation.

Reload PostgreSQL config with pg_ctl reload

Pass -D unless PGDATA is set in your shell; the pg_ctl reference requires one or the other:

$ pg_ctl reload
pg_ctl: no database directory specified and environment variable PGDATA unset
Try "pg_ctl --help" for more information.

$ pg_ctl -D /path/to/data reload
server signaled

A stopped server gives PID file ".../postmaster.pid" does not exist. To find the right directory, ask the server (superuser or pg_read_all_settings only):

SHOW data_directory;
SHOW config_file;
SHOW hba_file;

On Debian and Ubuntu, pg_ctl lives under /usr/lib/postgresql/<version>/ and is wrapped as pg_ctlcluster, so use sudo pg_ctlcluster 18 main reload; pg_lsclusters lists each cluster’s data directory.

Reload Postgres config from psql with pg_reload_conf()

Superusers can call pg_reload_conf(), and GRANT EXECUTE ON FUNCTION pg_reload_conf() TO role_name; extends that to another role. The t it returns means only that the signal was sent, not that the files were valid:

postgres=# SELECT pg_reload_conf();
 pg_reload_conf
----------------
 t
(1 row)

ALTER SYSTEM writes a setting to postgresql.auto.conf, and the reload applies it:

ALTER SYSTEM SET work_mem = '8MB';
SELECT pg_reload_conf();

Reload with systemctl reload postgresql or kill -HUP

On Debian and Ubuntu, sudo systemctl reload postgresql reloads every cluster set to start automatically, and sudo systemctl reload postgresql@18-main reloads one. The postgresql unit is only a meta unit; each cluster unit declares ReloadPropagatedFrom=postgresql.service, which forwards the reload. Other packages name the unit differently (systemctl list-units 'postgresql*' shows yours); the example unit in the server documentation implements reload as ExecReload=/bin/kill -HUP $MAINPID.

To send the signal yourself, the postmaster’s PID is the first line of postmaster.pid:

kill -HUP "$(head -1 /path/to/data/postmaster.pid)"

Which settings need a restart instead of a reload (pending_restart)

A setting’s context in pg_settings decides what a reload does. Many settings need only a reload, including log_min_duration_statement, which is how you start logging slow statements without a restart.

context After a reload Examples
postmaster Ignored until a restart shared_buffers, max_connections, wal_level, listen_addresses
sighup Applied everywhere max_wal_size, checkpoint_timeout, log_line_prefix
superuser, user Applied to existing sessions, except those that ran SET for that setting work_mem, log_min_duration_statement
superuser-backend, backend New connections only log_connections, log_disconnections

List every restart-only setting on your server:

SELECT name, context FROM pg_settings WHERE context = 'postmaster' ORDER BY name;

After a reload, skipped settings are flagged; setting still shows the running value (16384 blocks of 8kB, or 128MB):

postgres=# SELECT name, setting, pending_restart FROM pg_settings WHERE pending_restart;
      name      | setting | pending_restart
----------------+---------+-----------------
 shared_buffers | 16384   | t
(1 row)

A restart (pg_ctl -D /path/to/data restart or systemctl restart) clears the flag. A setting’s context can change between releases: autovacuum_max_workers needs a restart on 14 to 17 but only a reload on 18, which added the restart-only autovacuum_worker_slots as its ceiling.

I put the core steps in a script that builds a throwaway cluster on port 55432, runs them and deletes the cluster afterwards; it needs initdb, pg_ctl and psql on your PATH.

Check that the reload took effect

The postmaster logs each reload and each value it changes:

LOG:  received SIGHUP, reloading configuration files
LOG:  parameter "work_mem" changed to "8MB"

To see where a live value comes from, read source, sourcefile and sourceline in pg_settings (the last two need a superuser or pg_read_all_settings):

SELECT name, setting, source, sourcefile, sourceline
FROM pg_settings WHERE name = 'work_mem';

A sourcefile ending in postgresql.auto.conf means an ALTER SYSTEM value is overriding your edit, and a source of database, user or session means an ALTER DATABASE ... SET, ALTER ROLE ... SET or plain SET wins.

To catch mistakes before you reload, query pg_file_settings, which reads the files as they are now (superusers only, by default). A restart-only change shows up there too, as setting could not be applied:

SELECT sourcefile, sourceline, name, setting, error
FROM pg_file_settings WHERE error IS NOT NULL;

After the reload, SELECT pg_conf_load_time(); shows when the server last loaded the files; it doesn’t move after a syntax error. The log explains anything that didn’t apply:

Log line What it means
parameter "shared_buffers" cannot be changed without restarting the server A postmaster setting: the new value is ignored until a restart, and pending_restart is true.
invalid value for parameter "work_mem": "8XB" That line is rejected and the rest of the file applies (unaffected changes were applied).
syntax error in file "..." line 850 or unrecognized configuration parameter "work_memm" Nothing in the file applies, valid lines included (no changes were applied).
parameter "work_mem" removed from configuration file, reset to default You deleted or commented out the line, so the setting fell back to the built-in default.

A reload only logs a bad value or a syntax error and carries on with the old values, but a restart refuses to start on the same file (FATAL: configuration file "..." contains errors), so fix it now rather than at the next restart.

To find the log, SELECT pg_current_logfile(); returns its path while the logging collector is on. pg_lsclusters prints it on Debian and Ubuntu, and the Homebrew service writes to $(brew --prefix)/var/log/postgresql@18.log.

Reload pg_hba.conf without a restart

The same reload re-reads pg_hba.conf, so no restart is needed (on Windows, new connections pick up changes without a reload, as the documentation notes). Check the file first; pg_hba_file_rules reads it as it is now:

SELECT line_number, error FROM pg_hba_file_rules WHERE error IS NOT NULL;

If a line is bad, the reload logs the error and pg_hba.conf was not reloaded, and the server keeps the previous rules. A restart would fail with FATAL: could not load .../pg_hba.conf. A good reload logs nothing beyond the SIGHUP line.

Photo of author
Sudhir P. founded HeatWare.com in 1999 and has built and operated it full-stack ever since; it is now used by more than 88,000 people. He writes here about the PostgreSQL, MySQL, Linux and DevOps work that keeps it running. Articles are rewritten only after the commands in them have actually been run, and the verification scripts are published alongside them so anyone can check the claims. Reach him at blog@heatware.net.