DB Internals AtlasPostgreSQL 18.6 Home About

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

  1. Reads postgresql.conf and postgresql.auto.conf, checks the data directory and writes postmaster.pid (PID, data directory, port, socket directory, shared memory key).
  2. Allocates shared memory and semaphores. If this fails (for example huge pages or shared_buffers too large for the OS limits) the server does not start.
  3. Opens the listen sockets from listen_addresses, port and unix_socket_directories.
  4. 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.
LOG: starting PostgreSQL 18.6 on x86_64-pc-linux-gnu, compiled by gcc …, 64-bit LOG: listening on IPv4 address "0.0.0.0", port 5432 LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" LOG: database system was shut down at 2026-10-22 15:33:18 UTC LOG: database system is ready to accept connections

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:

LOG: client backend (PID 2996) was terminated by signal 9: Killed DETAIL: Failed process was running: select pg_sleep(60) LOG: terminating any other active server processes LOG: all server processes terminated; reinitializing LOG: database system was interrupted; last known up at 2026-10-22 15:33:18 UTC LOG: database system was not properly shut down; automatic recovery in progress LOG: redo starts at 0/175EC70 … LOG: database system is ready to accept connections

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

SignalSent byEffect
SIGHUPpg_ctl reload, pg_reload_conf()Re-read config files and pg_hba.conf, forward SIGHUP to children: LOG: received SIGHUP, reloading configuration files
SIGTERMpg_ctl stop -m smartSmart: refuse new connections, wait until all sessions end, then shut down.
SIGINTpg_ctl stop -m fast (default)Fast: terminate sessions (their transactions roll back), shutdown checkpoint, exit.
SIGQUITpg_ctl stop -m immediateImmediate: 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 checking max_connections; the last superuser_reserved_connections slots (and reserved_connections for pg_use_reserved_connections members) stay free for admins.
  • A stale postmaster.pid after 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 the child_process_kinds[] table (one entry per BackendType); the EXEC_BACKEND path 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

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