Architecture
Server startup sequence
Server startup is a postmaster state machine. PostgreSQL initializes the cluster environment, launches the startup process, performs WAL recovery when required, starts the appropriate background processes, and only then reaches a state that can serve normal connections.
In plain words
Starting PostgreSQL means starting one main process, the postmaster. Tools like pg_ctl start or systemd just launch it with the right data folder.
The postmaster reads the configuration, sets up the shared memory every session will use, writes a postmaster.pid file and starts listening for connections. Then it starts a helper, the startup process, whose job is to check whether the last shutdown was clean.
After a clean shutdown there is nothing to repair, so the server is ready almost at once. After a crash, the startup process first replays the write-ahead log (WAL) to bring the data files back to a consistent state, which can take a while. A standby server never really finishes this step: it keeps replaying WAL from its primary, and can accept read-only queries meanwhile.
Only when this is done does the server accept normal read-write connections. The animation lets you compare the three paths.
For DBAs and operators
The sequence
- Launch:
postgres -D ...,pg_ctl start, or the operating-system service starts the supervisor process.pg_ctl -wwaits until the PID-file status reports that the server is ready. - PM_INIT: the postmaster processes configuration and cluster paths, checks the data directory/control information, establishes the lock/PID file, initializes shared memory/semaphores, and opens the configured listen sockets.
- PM_STARTUP: it launches the startup process. PostgreSQL also starts infrastructure needed during startup/recovery, including the checkpointer/background writer and, when configured, PostgreSQL 18 I/O workers.
- StartupXLOG(): the startup process examines
pg_controland WAL/recovery configuration. A clean primary startup can finish quickly; an unclean state requires redo; archive/standby recovery can keep the startup process alive for much longer. - Recovery states: as soon as WAL redo begins (crash recovery as well as archive/standby recovery) the startup process signals the postmaster, which moves to
PM_RECOVERY; a clean start without redo goes straight fromPM_STARTUPtoPM_RUN. Once a consistent recovery point is reached and hot standby is enabled, the postmaster can enterPM_HOT_STANDBYand accept read-only connections while replay continues. - PM_RUN: after the startup process exits successfully at the end of startup/recovery, the postmaster enters normal running state and starts/maintains the remaining server processes allowed in that state.
Clean start versus crash recovery
A clean shutdown leaves control/WAL state that tells the next startup that normal shutdown completed. An immediate shutdown, power loss, operating-system crash, or unexpected postmaster/backend crash can leave the cluster requiring WAL redo. Recovery starts from the checkpoint REDO location and replays WAL needed to make the data files consistent; it is not simply "replaying from the checkpoint record".
Standby startup is deliberately different
During standby/archive recovery, the startup process may remain alive indefinitely. PostgreSQL can accept read-only sessions in PM_HOT_STANDBY while WAL continues to be restored/streamed and replayed. Promotion or completion of recovery eventually moves the server into PM_RUN.
What operators should watch
postmaster.pidexists while the server is running and carries a status used bypg_ctl -w; do not manually remove it while a server may still be alive.- Crash recovery can legitimately make startup take far longer than a clean start. Service-manager startup timeouts should account for this.
log_startup_progress_intervalcan report long startup/recovery operations such as data-directory synchronization or WAL redo.
PostgreSQL 18 source trail: postmaster.c defines the PM_INIT → PM_STARTUP → PM_RECOVERY/PM_HOT_STANDBY → PM_RUN state machine. startup.c shows StartupProcessMain() calling StartupXLOG(). See also the PostgreSQL 18 server-start documentation.
For developers: inside the source
PostmasterMain(), in order
SelectConfigFiles() read postgresql.conf / auto.conf
checkDataDir() permissions, PG_VERSION
CreateDataDirLockFile() postmaster.pid
LocalProcessControlFile() read pg_control
process_shared_preload_libraries() _PG_init() of extensions
InitializeShmemGUCs(), CreateSharedMemoryAndSemaphores()
ListenServerPort() … TCP and Unix sockets
RemovePgTempFiles()
UpdatePMState(PM_STARTUP); maybe_adjust_io_workers()
StartChildProcess(B_CHECKPOINTER), (B_BG_WRITER), (B_STARTUP)
ServerLoop()The helpers live in miscinit.c (lock file, process_shared_preload_libraries()), guc.c and ipci.c. The status line written into postmaster.pid (starting, ready, standby, stopping) and its line numbers are defined in pidfile.h; pg_ctl -w polls it in wait_for_postmaster_start() (pg_ctl.c).
The startup process
StartupProcessMain() calls StartupXLOG(). It reads ControlFileData (pg_control.h), then InitWalRecovery() looks for standby.signal/recovery.signal, finds the checkpoint record and decides whether redo is needed. If it is, PerformWalRecovery() runs the redo loop. At the end, PerformRecoveryXLogAction() writes an end-of-recovery record on promotion, otherwise it asks the checkpointer for an end-of-recovery checkpoint and waits for it.
How the postmaster learns about progress
The startup process uses SendPostmasterSignal() (pmsignal.c); the postmaster handles it in process_pm_pmsignal():
PMSIGNAL_RECOVERY_STARTED: sent byPerformWalRecovery()whenever redo begins, for crash recovery too;PM_STARTUP→PM_RECOVERY.PMSIGNAL_BEGIN_HOT_STANDBY: sent fromCheckRecoveryConsistency()once consistent with hot standby possible; →PM_HOT_STANDBY, "database system is ready to accept read-only connections".- Startup process exit code 0 →
PM_RUNinprocess_pm_child_exit();LaunchMissingBackgroundProcesses()then starts the WAL writer, autovacuum launcher, archiver and bgworkers allowed in that state.
Experiment and extend
log_min_messages = debug2shows the postmaster's internal messages, such as "postmaster received pmsignal signal".- TAP:
src/test/postmaster/t/003_start_stop.pl, and most ofsrc/test/recovery/t/(crash restart, PITR, standby). - Extensions loaded through
shared_preload_librariesrun_PG_init()in the postmaster before shared memory exists: request space inshmem_request_hook, initialise it inshmem_startup_hook, and register background workers there.
Parameters that shape this
data_directory shared_buffers listen_addresses port unix_socket_directories hot_standby restart_after_crash io_method io_workers log_startup_progress_interval
Related topics
Server shutdown modes Postmaster Startup process Crash recovery Checkpointer I/O workers Process model Write-ahead log (WAL)