2.1 The PostgreSQL Server Process Model

Key Takeaways

  • PostgreSQL implements a robust multi-process architecture based on the UNIX fork model, rather than a multi-threaded design, ensuring total memory address space isolation between concurrent client sessions.
  • The master supervisor process—historically named postmaster and executed via the postgres binary—listens for incoming connections, allocates shared memory, and spawns dedicated backend processes for authenticated clients.
  • Shared memory regions—primarily shared_buffers, wal_buffers, lightweight locks (LWLocks), heavyweight lock tables, and IPC semaphores—provide synchronized, high-performance inter-process coordination.
  • Private backend memory structures, such as work_mem, maintenance_work_mem, and temp_buffers, are allocated dynamically inside individual backend process address spaces and released upon operation completion.
  • Autonomous background helper processes—including the checkpointer, background writer (bgwriter), WAL writer, autovacuum launcher and workers, and archiver—execute asynchronous maintenance tasks to sustain engine throughput.
Last updated: September 2026

2.1 The PostgreSQL Server Process Model

[!NOTE] Architectural Heritage: PostgreSQL traces its roots back to the UC Berkeley POSTGRES project led by Michael Stonebraker. A core foundational design principle that persists today is its process-per-client model. Unlike database systems that multiplex client requests across worker threads within a single monolithic process (such as Microsoft SQL Server or MySQL), PostgreSQL treats operating-system-level process isolation as a fundamental reliability and fault-tolerance boundary.

Understanding the PostgreSQL server process model is essential for anyone administering production clusters or preparing for the PostgreSQL Associate certification. The database engine operates as a cooperative collection of distinct operating system processes that coordinate via shared memory segments and Inter-Process Communication (IPC) mechanisms.


The Master Supervisor Process: Postmaster (postgres)

At the epicenter of any running PostgreSQL instance sits the master supervisor daemon. Historically and colloquially known as the postmaster, this process is executed directly via the postgres binary (or invoked via service wrappers like pg_ctl).

Core Responsibilities of the Postmaster

  1. Initialization and Shared Memory Allocation: When the server boots, the postmaster reads the primary configuration files (postgresql.conf and postgresql.auto.conf), allocates the centralized shared memory segment (including shared_buffers and wal_buffers), and initializes inter-process synchronization primitives (semaphores and spinlocks).
  2. Network Connection Listening: The postmaster binds to specified network interfaces (listen_addresses) and TCP ports (default 5432), as well as the local UNIX domain socket (typically in /tmp or /var/run/postgresql).
  3. Spawning Background Helper Daemons: Immediately after initializing shared memory, the postmaster forks the critical background helper processes required for database operation, such as the checkpointer, background writer, WAL writer, and autovacuum launcher.
  4. Client Connection Handshake & Forking: The postmaster listens continuously for client connection requests. Upon receiving a connection request, it performs the initial socket handshake and immediately calls the POSIX fork() system call to spawn an independent, dedicated backend server process to handle that client.
  5. Lifecycle Supervision and Crash Recovery: The postmaster monitors all child processes. If a backend process terminates abnormally (for example, due to an unhandled segmentation violation in a third-party C extension), the postmaster detects the failure, initiates cluster-wide safety procedures, and coordinates recovery.
                          +--------------------------------+
                          |  Client Application (psql, etc)| 
                          +--------------------------------+
                                          │ (TCP / Socket: 5432)
                                          ▼
+--------------------------------------------------------------------------+
|                       Postmaster (postgres supervisor)                   |
+--------------------------------------------------------------------------+
       │ (fork)                         │ (fork)                  │ (fork)
       ▼                                ▼                         ▼
+----------------+              +----------------+       +-------------------+
| Backend Server |              | Backend Server |  ...  | Background Daemons|
|   Process 1    |              |   Process 2    |       | Checkpointer, etc.|
+----------------+              +----------------+       +-------------------+
       │                                │                          │
       └────────────────────────┬───────┴──────────────────────────┘
                                ▼
       +---------------------------------------------------+
       |              Shared Memory Segment                |
       | (shared_buffers, wal_buffers, Lock Tables, etc.)   |
       +---------------------------------------------------+

The Process-per-Client Model and Connection Lifecycle

When a client application (such as psql, an application server, or a microservice) establishes a connection to PostgreSQL, the lifecycle unfolds as follows:

  1. Socket Acceptance: The postmaster accepts the incoming TCP or UNIX domain socket connection.
  2. Fork Execution: The postmaster forks an identical child process—a dedicated backend process (also running the postgres binary with specific execution arguments). The child process inherits the open socket descriptor and attached shared memory segment pointers.
  3. Authentication Handshake: The postmaster yields control of the connection to the child backend. The child backend reads /var/lib/pgsql/data/pg_hba.conf and completes the client authentication protocol (e.g., verifying scram-sha-256 password hashes, SSL/TLS certificates, or GSSAPI tokens).
  4. Session Execution Loop: Once authenticated, the backend initializes session-specific parameters, enters an interactive query processing loop (exec_simple_query), parses SQL statements, optimizes execution plans, and executes transactions.
  5. Disconnection: When the client terminates the connection, the dedicated backend process exits cleanly, releasing all private memory back to the operating system kernel.

Architectural Benefits of Process Isolation

  • Fault Containment: If an errant query or a bug causes a backend process to crash, it cannot directly overwrite or corrupt the private memory address space of any other client backend.
  • Security Isolation: Each process operates under operating-system-level virtual memory protections, preventing unauthorized cross-session memory snooping.
  • Simpler Development: Developing custom C extensions does not require complex thread-safety guarantees across the entire query lifecycle, as each session runs within its own address space.

Architectural Tradeoffs: Connection Overhead

Because spawning an operating-system process via fork() consumes significantly more CPU and memory resources than spawning a lightweight thread, establishing hundreds or thousands of direct connections can degrade operating system scheduling efficiency. In production PostgreSQL architectures, connection poolers such as PgBouncer or pgpool-II are universally deployed to maintain a lean pool of pre-forked backend connections.


Memory Architecture: Shared Memory vs. Private Backend Memory

PostgreSQL memory is strictly partitioned into two fundamental tiers: Shared Memory (accessible by all processes) and Private Backend Memory (allocated per backend process).

+-----------------------------------------------------------------------------------+
|                             PostgreSQL Memory Layout                              |
+-----------------------------------------------------------------------------------+
|  SHARED MEMORY (Allocated at server startup, shared across all processes)          |
|  ┌─────────────────────────┐ ┌──────────────────────┐ ┌────────────────────────┐  |
|  | shared_buffers (25% RAM)| | wal_buffers (16MB)   | | Lock Tables & LWLocks  |  |
|  └─────────────────────────┘ └──────────────────────┘ └────────────────────────┘  |
+-----------------------------------------------------------------------------------+
|  PRIVATE BACKEND MEMORY (Allocated dynamically within individual backend processes)|
|  ┌─────────────────────────┐ ┌──────────────────────┐ ┌────────────────────────┐  |
|  | work_mem (per sort/hash)| | maintenance_work_mem | | temp_buffers (session) |  |
|  └─────────────────────────┘ └──────────────────────┘ └────────────────────────┘  |
+-----------------------------------------------------------------------------------+

1. Shared Memory Structures

Shared memory is initialized once by the postmaster during startup via POSIX or System V shared memory interfaces (mmap or shmget):

  • shared_buffers: The central caching engine for database table and index data pages. When a query accesses a relation, PostgreSQL loads the required 8KB disk blocks into shared_buffers. Subsequent reads for the same blocks are served directly from RAM without disk I/O. Production sizing typically defaults to approximately 25% of total system RAM.
  • wal_buffers: The staging cache for Write-Ahead Log (WAL) records before they are flushed (fsync) to persistent storage in pg_wal. Sized automatically by default to 1/32 of shared_buffers (typically capped at 16MB), which accommodates active transaction bursts.
  • Lock Management Tables: Shared hash tables that maintain cluster-wide concurrency controls, including heavyweight locks (table, row, and page locks) and Lightweight Locks (LWLocks) protecting shared memory data structures.
  • IPC Semaphores and Spinlocks: Low-level synchronization primitives ensuring that multiple backends do not simultaneously mutate the same shared memory buffers.

2. Private Backend Memory Structures

Private memory is allocated out of the process's individual heap and is completely isolated from other backends:

  • work_mem: Sized per sorting or hashing operation! It is used for ORDER BY, DISTINCT, merge joins, hash joins, and hash-based aggregations.

    [!IMPORTANT] The work_mem Multiplier Effect: A single SQL query containing multiple sort and join operations can allocate multiple work_mem buffers concurrently. Furthermore, each concurrent client can execute such queries simultaneously. If work_mem is set to 64MB, and a query contains three sorts and two hash joins, that single query can consume up to 5 * 64MB = 320MB of RAM. Sizing work_mem too aggressively under high max_connections can trigger the Linux Out-Of-Memory (OOM) Killer!

  • maintenance_work_mem: Allocated for resource-intensive administrative maintenance operations, including VACUUM, CREATE INDEX, REINDEX, and adding foreign key constraints. Because administrative tasks run far less frequently than standard queries, this parameter can be sized substantially larger (e.g., 512MB to 2GB) to dramatically accelerate index building and vacuuming.
  • temp_buffers: Allocated by a backend to hold temporary tables created via CREATE TEMP TABLE. These buffers reside in private memory and require no shared locking or WAL logging.
Memory StructureClassificationScopeDefault SettingConfiguration Context
shared_buffersShared MemoryEntire Cluster128MB (system default)postmaster (Restart)
wal_buffersShared MemoryEntire Cluster-1 (1/32 of shared_buffers)postmaster (Restart)
work_memPrivate BackendPer Operation Node4MBuser (Session dynamic)
maintenance_work_memPrivate BackendPer Maintenance Task64MBuser (Session dynamic)
temp_buffersPrivate BackendPer User Session8MBuser (Session dynamic)

Core Background Helper Processes

To ensure high transaction throughput without placing the burden of asynchronous disk I/O onto client-facing backends, the postmaster supervises a fleet of specialized background helper processes:

1. The Checkpointer (checkpointer)

  • Operational Purpose: Coordinates cluster-wide checkpoints. A checkpoint is a synchronization point where all modified (dirty) shared buffers are flushed to persistent disk, and the pg_control file is updated with the latest checkpoint Redo location.
  • Durability Role: During a crash, PostgreSQL replays WAL records starting only from the last completed checkpoint. By periodically issuing checkpoints (governed by checkpoint_timeout and max_wal_size), the checkpointer bounds the total crash recovery time.

2. The Background Writer (bgwriter)

  • Operational Purpose: Continually scans shared_buffers in a gentle, metered loop to write dirty pages out to storage.
  • Throughput Role: When a client backend needs to read an 8KB page from disk, it must allocate a clean buffer in shared_buffers. If all buffers are dirty, the backend would stall while synchronously writing a dirty page to disk itself. The bgwriter prevents these backend stalls by proactively ensuring a steady supply of clean, reusable shared buffers.

3. The WAL Writer (walwriter)

  • Operational Purpose: Periodically flushes buffered WAL records from wal_buffers to the disk files in pg_wal (wal_writer_delay).
  • Efficiency Role: Even if no client issues an immediate COMMIT, the walwriter ensures write-ahead log data is consistently committed to disk in large sequential batches, reducing transactional latency.

4. Autovacuum Launcher and Autovacuum Workers

  • Launcher Daemon: A persistent supervisor process that inspects database catalogs and monitors table modification activity tracked by cumulative statistics.
  • Worker Processes: When a table surpasses its dead-tuple threshold (autovacuum_vacuum_threshold + autovacuum_vacuum_scale_factor * table_tuples), the launcher spawns an autovacuum worker process. The worker scans the table, reclaims storage space occupied by dead Multi-Version Concurrency Control (MVCC) row versions, updates the Free Space Map (_fsm) and Visibility Map (_vm), and freezes old transaction IDs to prevent transaction ID wraparound.

5. Cumulative Statistics System & Background Workers

  • Historical UDP Daemon vs. Modern Engine: In versions prior to PostgreSQL 15, a dedicated stats collector process collected activity metrics over a local UDP socket. In PostgreSQL 15 and later, statistics are maintained directly in a shared memory hash table, managed by lightweight background workers, eliminating IPC bottlenecks.
  • Administrative Views: Feeds activity monitoring views such as pg_stat_activity, pg_stat_database, and pg_stat_user_tables.

6. The Archiver (archiver)

  • Operational Purpose: When continuous archiving is enabled (archive_mode = on), the archiver is spawned to execute the archive_command or invoke archive_library. It offloads completed 16MB WAL segment files from pg_wal to external backup repositories (e.g., S3, NFS, or Barman), creating the stream required for Point-In-Time Recovery (PITR).

Memory Isolation, Fault Tolerance & Crash Recovery

What happens when an individual backend process encounters a fatal error or crashes?

  1. Hardware Memory Protection: Because each backend has its own private virtual memory address space, a corrupted pointer in Backend A cannot directly corrupt the private memory of Backend B.
  2. Shared Memory Invalidation: However, Backend A had direct, active pointers into the centralized shared memory region (including shared_buffers and lock tables). If Backend A crashed while holding a spinlock or modifying a shared data structure, the integrity of shared memory can no longer be guaranteed.
  3. Postmaster Intervention: The postmaster immediately receives a SIGCHLD signal indicating the abnormal termination of Backend A.
  4. Emergency Sibling Termination: To prevent corrupted shared memory state from propagating to persistent disk, the postmaster transmits a SIGQUIT signal to all remaining active backend processes, abruptly disconnecting all client sessions.
  5. Shared Memory Reset & Recovery: The postmaster re-initializes shared memory structures, enters crash recovery mode, inspects pg_control, and invokes WAL replay starting from the last valid checkpoint. Once the WAL replay brings the database back to a crash-consistent state, normal client connections are once again accepted.

Practical Inspection via SQL

Administrators can inspect active backend processes directly using PostgreSQL's system administrative functions and catalog views:

-- Retrieve the operating system Process ID (PID) of the current backend session
SELECT pg_backend_pid();

-- Inspect active backend processes and background workers
SELECT pid, usename, client_addr, state, backend_type, query
FROM pg_stat_activity
ORDER BY backend_type, pid;

In the resulting output, the backend_type column identifies the specific role of each process: client backend, checkpointer, background writer, walwriter, autovacuum launcher, or archiver.


Exam Tips and Common Pitfalls

  • Exam Trap: Threading vs. Forking: If an exam question asks how PostgreSQL handles concurrent client connections by default, remember: PostgreSQL spawns a dedicated operating system process per connection via fork(), NOT a new thread.
  • Exam Trap: Memory Scope: Remember that shared_buffers is allocated once for the cluster, whereas work_mem is allocated dynamically per operation node within a query. An exam scenario asking for the maximum potential memory consumption of a 100-connection database must account for the work_mem multiplier.
  • Exam Trap: Checkpointer vs. Background Writer: The checkpointer writes dirty buffers to fulfill a scheduled or forced checkpoint synchronization point (updating pg_control). The background writer (bgwriter) writes dirty buffers in small, continuous batches specifically to ensure that client backends find clean buffers without waiting on disk writes.
Loading diagram...
PostgreSQL Architecture: Process Hierarchy and Memory Interaction
Test Your Knowledge

When an authenticated client connects to a PostgreSQL database server, how does the engine handle the connection to execute the client's queries?

A
B
C
D
Test Your Knowledge

A PostgreSQL server has 40 connected client backends. Which of the following parameters is allocated exactly once for the whole cluster in the shared memory segment created by the postmaster at startup, rather than separately inside each backend process?

A
B
C
D
Test Your Knowledge

Which background helper process is specifically tasked with continually scanning shared_buffers in small, regular intervals to write modified (dirty) pages to persistent storage, ensuring that incoming backend processes can immediately acquire clean buffers without experiencing disk write stalls?

A
B
C
D