Systemd & Service Management
Production PostgreSQL on Linux runs under systemd (or an equivalent init). Knowing start, stop, reload, and status maps directly to incident response and safe deploys.
Recipe
# systemd (Debian/Ubuntu package names vary)
sudo systemctl start postgresql@18-main
sudo systemctl status postgresql@18-main
sudo systemctl reload postgresql@18-main
# pg_ctl equivalents (any install)
sudo -u postgres pg_ctl -D /var/lib/postgresql/18/main start
sudo -u postgres pg_ctl -D /var/lib/postgresql/18/main reload
sudo -u postgres pg_ctl -D /var/lib/postgresql/18/main statusWhen to reach for this: Bootstrapping a host, applying pg_hba.conf changes, or recovering from a failed stop during maintenance.
Working Example
# Inspect unit and environment
systemctl cat postgresql@18-main
systemctl show postgresql@18-main -p Environment -p ExecStart
# Graceful reload after config change
sudo systemctl reload postgresql@18-main
# Confirm reload picked up hba
sudo -u postgres psql -c "SELECT pg_reload_conf();"# Override fragment: /etc/systemd/system/postgresql@18-main.service.d/override.conf
[Service]
Environment=PGDATA=/data/pgdata
TimeoutStartSec=300
TimeoutStopSec=300sudo systemctl daemon-reload
sudo systemctl restart postgresql@18-mainWhat this demonstrates:
reloadsends SIGHUP - appliespg_hba.confand many GUCs without dropping connectionsdaemon-reloadrequired after unit file editsTimeoutStopSecgives checkpoints time on large shared_buffers systems
Deep Dive
systemd vs pg_ctl Mapping
| Intent | systemd | pg_ctl |
|---|---|---|
| Start | systemctl start | pg_ctl start -D $PGDATA |
| Stop (fast) | systemctl stop | pg_ctl stop -m fast -D $PGDATA |
| Stop (immediate) | N/A (use pg_ctl) | pg_ctl stop -m immediate |
| Reload | systemctl reload | pg_ctl reload -D $PGDATA |
| Status | systemctl status | pg_ctl status -D $PGDATA |
| Restart | systemctl restart | pg_ctl restart -D $PGDATA |
Stop Modes
# smart - wait for clients (default)
pg_ctl stop -D $PGDATA -m smart
# fast - rollback active transactions, disconnect clients
pg_ctl stop -D $PGDATA -m fast
# immediate - crash-like shutdown, recovery on next start
pg_ctl stop -D $PGDATA -m immediate- Production maintenance: prefer fast unless you need smart drain.
- immediate risks longer crash recovery - use only when fast hangs.
Enable at Boot
sudo systemctl enable postgresql@18-main
sudo systemctl is-enabled postgresql@18-mainenablecreates symlinks for multi-user.target.- Cloud VMs with ephemeral disks still enable the unit - data dir must persist separately.
Logs
journalctl -u postgresql@18-main -f
journalctl -u postgresql@18-main --since "1 hour ago" -p err- Package installs often log to stderr captured by journald.
- Also check
log_directoryinpostgresql.conffor CSV/json file logs.
Gotchas
- Restart instead of reload for postmaster GUCs -
shared_bufferschanges need restart; reload silently keeps old value withpending_restart. Fix:SELECT name FROM pg_settings WHERE pending_restart; - Wrong PGDATA in unit - Multiple clusters on one host need distinct instances (
postgresql@18-main). Fix:systemctl catandSHOW data_directory;must agree. - Stop timeout too short - systemd kills postgres mid-checkpoint. Fix: Raise
TimeoutStopSecto 300s+ on large systems. - Running pg_ctl as root - Server refuses root-owned operations. Fix:
sudo -u postgres pg_ctl ... - reload during heavy DDL - Reload itself is safe, but restart during migration is not. Fix: Use reload for hba; schedule restart in maintenance window.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Patroni-managed unit | HA failover automation | Single-node dev laptop |
Docker docker compose restart | Containerized dev | You need journald integration |
pg_ctl only (no systemd) | BSD, manual tar installs | Standard Linux prod without init script |
FAQs
reload vs restart?
Reload applies SIGHUP (hba, many GUCs). Restart stops and starts postmaster (required for shared_buffers, max_connections, etc.).
How do I know if Postgres is running?
systemctl is-active postgresql@18-main or pg_isready -h localhost -p 5432.
Safe stop before filesystem snapshot?
systemctl stop (fast mode) quiesces writes. Verify no connections with pg_stat_activity before snapshot.
Multiple clusters on one host?
Use instance units (postgresql@18-main, postgresql@18-analytics) each with its own PGDATA.
Failed start after config edit?
Check journalctl -u postgresql@18-main -n 50. Often a typo in postgresql.conf - fix and start again.
Related
- postgresql.conf Essentials - which GUCs need restart
- pg_hba.conf & Authentication - reload after hba edits
- initdb & Data Directory - PGDATA path in unit files
Stack versions: This page was written for PostgreSQL 18.4 (stable 18, maintenance 17), pgvector 0.8+, PgBouncer 1.x, Patroni 3.x, and PostGIS 3.5+.