Skip to main content
RunBook Academy

PostgreSQLXII · WAL, Checkpoints and Crash RecoveryWAL

Shutdown modes and their recovery consequences

Intermediate⏱ ~25 minpg_ctl

What you'll learn

  • Choose the correct shutdown mode for a given situation
  • Explain why smart shutdown can make a cluster unavailable without completing
  • Predict whether a given stop will require recovery on restart
  • Configure systemd so that a host reboot shuts PostgreSQL down correctly

Prerequisites

Verified against PostgreSQL 18.x · PostgreSQL (comparison targets) 17.11, 16.15 · PostgreSQL (support calendar) 18, 17, 16, 15, 14 supported · pgBackRest 2.59.1 · PgBouncer 1.25.2 · Patroni 4.1.5 · Ubuntu (host baseline) 26.04 LTS · 2026-08-27

Not yet marked complete on this device.

Three modes, and the one that sounds most considerate is the one most likely to cause an outage.

Read-only / Safewhat PostgreSQL says about them
$ pg_ctl --help
Shutdown modes are:
smart       quit after all clients have disconnected
fast        quit directly, with proper shutdown (default)
immediate   quit without complete shutdown; will lead to recovery on restart
ModeSignalExisting sessionsClean shutdown?Recovery on restart?
smartSIGTERMWaits for them to leaveYesNo
fastSIGINTDisconnected, transactions rolled backYesNo
immediateSIGQUITKilledNoYes

Fast: the default and usually the answer

Configuration changefast shutdown with a session holding an uncommitted INSERT
$ pg_ctl -D $PGDATA -m fast -w stop
waiting for server to shut down....done

elapsed: 119 ms

-- on restart:
LOG:  database system was shut down at 2026-08-27 21:13:23 UTC
LOG:  database system is ready to accept connections

-- the uncommitted rows:
SELECT count(*) FROM crashtest WHERE id > 2000000;  ->  0

119 milliseconds. The session was disconnected, its uncommitted work discarded — correctly, since it was never committed — and the shutdown completed cleanly, so the restart needed no recovery.

fast is the right choice for planned maintenance, deployments, failovers and almost everything else.

Smart: the trap

Service impact possiblesmart shutdown with one ordinary idle session connected
$ pg_ctl -D $PGDATA -m smart -w -t 10 stop
pg_ctl: server does not shut down
HINT: The "-m fast" option immediately disconnects sessions rather than
waiting for session-initiated disconnection.

elapsed: 10 s, and the server was still running
Service impact possibleand, while that shutdown was pending
$ psql -U postgres -c "SELECT 'still up'"
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432"
failed: FATAL:  the database system is shutting down

Immediate: a deliberate crash

Destructiveimmediate shutdown, and the restart it produces
$ pg_ctl -D $PGDATA -m immediate -w stop
waiting for server to shut down....done

-- on restart:
LOG:  database system was interrupted; last known up at 2026-08-27 21:14:24 UTC
LOG:  database system was not properly shut down; automatic recovery in progress
LOG:  redo is not required
LOG:  checkpoint complete: wrote 0 buffers (0.0%) ... distance=0 kB, estimate=0 kB
LOG:  database system is ready to accept connections

The was interrupted and not properly shut down lines are identical to the SIGKILL case in lesson XII-06. Immediate shutdown is a crash that you asked for.

redo is not required appears here only because a checkpoint had completed moments earlier and nothing had been written since. On a busy cluster the same command produces a full redo. The mode does not choose how much recovery is needed; the distance since the last checkpoint does.

Legitimate uses: a hung cluster that will not respond to fast, and a cluster you are about to discard. Not legitimate: as a faster way to stop a healthy server, because the time saved on the way down is paid back with interest on the way up.

Systemd, and the reboot you did not think about

A host reboot sends SIGTERM to services, which for PostgreSQL is smart mode. With a pooler holding connections, that stops nothing; systemd then waits for TimeoutStopSec — 90 seconds by default — and sends SIGKILL, which is an unclean crash.

So a routine reboot produces a 90-second hang followed by a crash, on a cluster that would have stopped cleanly in 119 milliseconds.

The packaged units on major distributions handle this, and it is worth confirming rather than assuming:

systemctl cat postgresql@18-main | grep -E 'KillSignal|TimeoutStopSec|ExecStop'

What you want to see is either an ExecStop invoking pg_ctl with -m fast, or KillSignal=SIGINT, which is the signal fast mode uses.

[Service]
KillSignal=SIGINT
TimeoutStopSec=300
KillMode=mixed

TimeoutStopSec should exceed the time a fast shutdown genuinely takes on your cluster — the shutdown checkpoint has to write every dirty buffer, which on a large shared_buffers is not instant.

What to take from this

  • fast is the default and the right answer almost always. Measured at 119 ms.
  • smart waits indefinitely and refuses new connections. One idle session blocked it for its full timeout.
  • immediate is a deliberate crash. The restart log is identical to a SIGKILL.
  • A host reboot sends SIGTERM, which is smart mode. Check your systemd unit uses -m fast or KillSignal=SIGINT.
  • CHECKPOINT before stopping, so the shutdown checkpoint is small.
  • Confirm with pg_controldata: Database cluster state: shut down.

Cross-course references

  • Linux for Production Sysadmins — Part VII (systemd) covers TimeoutStopSec and what expires into a kill, which is how a smart shutdown quietly becomes a crash.
  • Docker & Containers — Part VI (Container lifecycle) covers docker stop’s grace period, which is the same trap with a different default.
  • Kubernetes for Production Sysadmins — Part X (Pod termination and signals) covers terminationGracePeriodSeconds, which is where this goes wrong on a cluster nobody tuned.

Quiz

Knowledge check · 6 questions

  1. Q1. An operator issues a smart shutdown on a cluster fronted by a connection pooler. What happens?

  2. Q2. A host reboot leaves PostgreSQL performing crash recovery on every start, despite the reboot being planned. What is the most likely cause?

  3. Q3. A fast shutdown on a cluster with 64 GB of shared_buffers is taking several minutes. Why, and what would have helped?

  4. Q4. Which are true of an immediate shutdown? Select all that apply.

  5. Q5. After stopping a cluster, pg_controldata reporting 'Database cluster state: shut down' is the proof that the stop was clean.

  6. Q6. Write the sequence you would follow to stop a large production cluster for maintenance, and say why each step is there.

Passing score: 75%. Answers are checked in this browser.