Background processes
Postmaster
The postmaster is the first PostgreSQL process. It creates shared memory, starts the helper processes, accepts connections, and watches over every child it has started.
In plain words
When you start PostgreSQL you really start one program: the postmaster. It is the parent of every other PostgreSQL process. First it reserves the big block of shared memory that all processes will use, then it starts the helpers (checkpointer, background writer, WAL writer, autovacuum launcher and others) and opens the network port.
After that it mostly waits. Each time a client connects, the postmaster makes a copy of itself (a fork) and hands the connection to that new backend process. The postmaster itself never runs queries and never touches table data, which keeps it simple and very unlikely to crash.
It also acts as a supervisor. If a child process dies in an unexpected way, the postmaster cannot trust shared memory anymore, so it stops all processes, resets shared memory and runs crash recovery. Every session is disconnected for a few seconds, but no committed data is lost.
Finally, it is the process you talk to when you reload the configuration (pg_ctl reload) or stop the server (pg_ctl stop).
For DBAs and operators
Start-up sequence
- Reads
postgresql.confandpostgresql.auto.conf, checks the data directory and writespostmaster.pid(PID, data directory, port, socket directory, shared memory key). - Allocates shared memory and semaphores. If this fails (for example huge pages or
shared_bufferstoo large for the OS limits) the server does not start. - Opens the listen sockets from
listen_addresses,portandunix_socket_directories. - Launches the startup process, the checkpointer, the background writer and (since PostgreSQL 18, with
io_method = worker) the I/O workers. When the startup process has finished recovery, the postmaster launches the WAL writer, autovacuum launcher, archiver and background workers such as the logical replication launcher.
Seeing it
The postmaster does not appear in pg_stat_activity. In ps it keeps its original command line (for example /usr/lib/postgresql/18/bin/postgres -D /var/lib/postgresql/18/main) while its children show titles such as postgres: checkpointer. Its PID is the first line of postmaster.pid, and every child has it as parent PID:
SELECT pg_postmaster_start_time(),
now() - pg_postmaster_start_time() AS uptime;
-- children: ps -o pid,ppid,args --ppid $(head -1 $PGDATA/postmaster.pid)Supervising children
When a child exits, the kernel sends SIGCHLD and the postmaster reaps it. A clean exit (code 0, or code 1 for some processes) just frees the slot; helper processes are simply started again. Any other exit, for example kill -9 or the Linux OOM killer, means shared memory might be corrupt. The postmaster then sends SIGQUIT to every child and reinitialises:
The same happens if an auxiliary process such as the checkpointer, WAL writer or archiver is killed with signal 9. With restart_after_crash = off the postmaster exits instead, which is what cluster managers such as Patroni prefer so they can fail over. The cumulative statistics are reset by a crash restart (see statistics system).
Never kill -9 a backend to stop a query: it disconnects everyone. Use pg_cancel_backend() or pg_terminate_backend(). On Linux, set vm.overcommit_memory = 2 or protect the postmaster with oom_score_adj so the OOM killer does not trigger crash restarts.
Signals it understands
| Signal | Sent by | Effect |
|---|---|---|
SIGHUP | pg_ctl reload, pg_reload_conf() | Re-read config files and pg_hba.conf, forward SIGHUP to children: LOG: received SIGHUP, reloading configuration files |
SIGTERM | pg_ctl stop -m smart | Smart: refuse new connections, wait until all sessions end, then shut down. |
SIGINT | pg_ctl stop -m fast (default) | Fast: terminate sessions (their transactions roll back), shutdown checkpoint, exit. |
SIGQUIT | pg_ctl stop -m immediate | Immediate: kill all children at once, no checkpoint; next start runs crash recovery. |
Support notes
- "
FATAL: sorry, too many clients already" comes from a new backend checkingmax_connections; the lastsuperuser_reserved_connectionsslots (andreserved_connectionsforpg_use_reserved_connectionsmembers) stay free for admins. - A stale
postmaster.pidafter a host crash is handled automatically; never delete it while a postmaster is running. - Connection storms are expensive because every connection is a
fork()plus authentication. Use a pooler.
For developers: inside the source
Where it lives
postmaster.c:PostmasterMain(),ServerLoop(), the state machine and child bookkeeping.launch_backend.c:postmaster_child_launch()and thechild_process_kinds[]table (one entry perBackendType); theEXEC_BACKENDpath used on Windows.pmchild.c: child slots (AssignPostmasterChildSlot(),AllocDeadEndChild()).pmsignal.c: how children talk back (SendPostmasterSignal()).
Start-up call flow
PostmasterMain() runs, in order: CreateDataDirLockFile() (postmaster.pid) → process_shared_preload_libraries() → process_shmem_requests() → InitializeShmemGUCs() → CreateSharedMemoryAndSemaphores() → ListenServerPort() per address → StartChildProcess(B_CHECKPOINTER), B_BG_WRITER, then B_STARTUP → ServerLoop(). Everything else is started later by LaunchMissingBackgroundProcesses(), which looks at pmState (PM_STARTUP, PM_RECOVERY, PM_HOT_STANDBY, PM_RUN, then the PM_STOP_BACKENDS … PM_NO_CHILDREN shutdown states) and starts the WAL writer only in PM_RUN, the archiver depending on archive_mode, and so on.
The event loop
Signal handlers only set flags (pending_pm_child_exit, pending_pm_reload_request …). ServerLoop() waits in WaitEventSetWait() on the listen sockets and its latch, then calls process_pm_shutdown_request(), process_pm_reload_request(), process_pm_child_exit() and process_pm_pmsignal(). A new connection goes AcceptConnection() → BackendStartup() → postmaster_child_launch() → fork_process(). The postmaster does not authenticate: that happens in the child, so a slow client cannot block it.
Children are tracked as PMChild structs (postmaster.h): pid, child_slot, bkend_type, rw for background workers. process_pm_child_exit() reaps with waitpid(-1, …, WNOHANG); an unexpected status leads to HandleChildCrash(), which sends SIGQUIT to everyone, and PostmasterStateMachine() later re-creates shared memory and restarts the startup process. Children ask the postmaster for things through PMSIGNAL_* reasons, for example PMSIGNAL_START_AUTOVAC_WORKER or PMSIGNAL_BACKGROUND_WORKER_CHANGE.
Extension hooks
Libraries in shared_preload_libraries are loaded in the postmaster, so their _PG_init() can set shmem_request_hook (call RequestAddinShmemSpace() / RequestNamedLWLockTranche()), shmem_startup_hook, and call RegisterBackgroundWorker() (bgworker.c). Because backends are forked, they inherit everything set up here.
Experimenting
- TAP tests:
src/test/postmaster/t/(connection limits, start/stop) and013_crash_restart.pl(kill -9 a backend and check the restart). log_min_messages = debug2showsforked new client backend, pid=… socket=…fromBackendStartup().src/test/modules/worker_spiis the reference background worker.
Parameters that shape this
max_connections superuser_reserved_connections reserved_connections listen_addresses port unix_socket_directories restart_after_crash shared_buffers autovacuum_worker_slots max_worker_processes
Related topics
Server startup sequence Server shutdown modes Process model Client backend Startup process Crash recovery Checkpointer Logger (logging collector) Client authentication Memory architecture