work_mem
Per-operation memory for sorts and hash joins: too low spills to disk; too high times active connections crashes the whole server.
- Category
- Resource / Memory
- Default
- 4MB (4096 kB)
- Type
- integer (kB)
- Context
- user
- Blast Radius
- Cluster
- Versions
- PG 14 – 18
- Severity
- ⚡ 5 / 5
- Reviewed
- 2026-06-19
What It Actually Does
work_mem sets the maximum memory for each individual sort or hash operation — not per query, not per connection.
It is a ceiling, not a reservation: only the memory actually needed (up to the limit) is allocated.
A single complex query with 3 sorts and 2 hash joins can open 5 separate work_mem workspaces simultaneously.
Multiply by concurrent connections to get the real memory exposure.
What it controls
work_mem × hash_mem_multiplierWhat it does NOT control
shared_buffers (a completely separate allocation)“I raised work_mem to 256MB so each connection gets 256MB.” — False. Each operation node gets up to 256MB. A query with 4 nodes × 50 connections = 200 potential workspaces × 256MB = 50GB exposure on a 32GB server. This is the exact shape that triggers OOM kills.
Lab Validated Evidence
Key Findings
Performance Curve
external merge Disk to quicksort Memory at 64MB.
The sort workspace requires 49,153kB (~48MB) of resident memory. Below that: disk spill.
At 64MB: zero temp writes. Curve is flat past the flip — 64MB = 128MB = 256MB all measure 49153kB and ~655ms.
work_mem is a ceiling, not a reservation.| work_mem | Sort Method | Median (ms) | Reps |
|---|---|---|---|
| 64kB | Disk | 1003.4 | 3 |
| 1MB | Disk | 867.2 | 3 |
| 4MB | Disk | 730.8 | 3 |
| 16MB | Disk | 741.2 | 3 |
| 32MB | Disk | 759.3 | 3 |
| 64MB | Memory ← flip point | 657.8 | 3 |
| 128MB | Memory | 659.2 | 3 |
| 256MB | Memory | 655.1 | 3 |
The speedup above is specific to narrow integer keys, non-parallel. A second benchmark (wide text payload + 2 parallel workers) showed the opposite: disk sort 1815ms beat in-memory sort 5831ms. Parallel external merge on NVMe can be faster than serial in-memory quicksort for wide rows. Measure your actual workload.
Failure Story
Trigger: 6 concurrent sessions —
SET work_mem='1GB'; SELECT payload FROM wm ORDER BY payload OFFSET 2000000;-
1Configuration ChangeDBA raises
work_memfrom 4MB to 1GB cluster-wide viaALTER SYSTEM+pg_reload_conf()to fix a slow analytics report. No restart required — change is live immediately for new sessions. -
2Memory Pressure BuildsSix existing and new sessions immediately run sort queries. Each sort node allocates up to 1GB. The sort workspace per query reaches the required ~48MB — but each of 6 backends also accumulates anon-rss (~103MB each, ~2× EXPLAIN output). Combined with 128MB shared_buffers, RAM is exhausted.
-
3OOM KillLinux kernel’s OOM killer targets the largest PostgreSQL backend process.
chevron_right Kernel OOM evidence — dmesg
Memory cgroup out of memory: Killed process 25608 (postgres) total-vm:471048kB, anon-rss:103516kB, file-rss:62672kB, oom_score_adj:0 -
4PostgreSQL Restarts Entire ClusterThe postmaster detects a backend process killed by signal 9. It terminates ALL server processes and reinitialises — not just the one that was OOM-killed.
chevron_right PostgreSQL log evidence
2026-06-19 00:12:18.861 UTC [1] LOG: server process (PID 133) was terminated by signal 9: Killed 2026-06-19 00:12:18.862 UTC [1] LOG: terminating any other active server processes 2026-06-19 00:12:18.874 UTC [1] LOG: all server processes terminated; reinitializing -
5All Connections DropEvery client — OLTP transactions, read replicas, application pools — loses its database connection simultaneously. This is a full cluster availability event, not a slow query incident. Recovery time measured at 784ms (pg_reload_conf after RESET, pgc18).
Safe Usage Guide
Recommended
ALTER ROLE analytics_role SET work_mem = '256MB'; — keeps the multiplier bounded.
SET LOCAL work_mem = '256MB'; inside a transaction — reverts at COMMIT.
shared_buffers.
pg_stat_database.temp_bytes to detect spills. Rising values = sorts overflowing the current work_mem ceiling.
ALTER SYSTEM is often blocked.
Avoid
hash_mem_multiplier. Hash joins get work_mem × hash_mem_multiplier. Default = 2.0 since PG15.
Before / After Comparison
Version Matrix
| Version | Default | Context | hash_mem_multiplier default | Notable Change |
|---|---|---|---|---|
| PG 14 | 4096 kB | user | 1 | hash_mem_multiplier=1 |
| PG 15 | 4096 kB | user | 2 | hash_mem_multiplier=2 (changed) |
| PG 16 | 4096 kB | user | 2 | — |
| PG 17 | 4096 kB | user | 2 | — |
| PG 18 | 4096 kB | user | 2 | — |
Source: pg_settings captured from pgc14–pgc18 (2026-06-24). work_mem default unchanged across all versions. hash_mem_multiplier changed from 1 → 2 in PG15. This doubles the memory budget for all hash operations.
Parameter Interactions
peak_mem = work_mem × 2 × concurrent_queries
hash_peak = work_mem × hash_mem_multiplier
sort_mem = work_mem × (1 + workers)
available = total_RAM − shared_buffers
Operational Metadata
Common Pitfalls
Monitoring & Early Warning workspace_premium PRO
temp_files=0, temp_bytes=0 after pg_stat_reset.After 3 narrow-key sorts at work_mem=4MB: temp_files=3, temp_bytes=69MB.
After 3 sorts at work_mem=64MB (in-memory): 0 new temp_bytes.
Rising temp_bytes = sorts spilling to disk right now.
Monitoring SQL Queries
All 4 queries were executed against pgc17 (PostgreSQL 17.10) and outputs captured. Pro members get the exact SQL + captured output for spill detection, active query watch, current setting check, and per-role override audit.
Per-Workload Guide workspace_premium PRO
The right work_mem depends entirely on your workload archetype.
OLTP gets zero benefit from raising it. Analytics and ETL get
measurable gains. Setting it globally is almost always wrong.
Pro members get the full measured
per-archetype breakdown with real EXPLAIN ANALYZE output.
Per-Workload Benchmark Results
4 workload archetypes run against pgc17. Real EXPLAIN ANALYZE output, measured latencies, and per-archetype recommendations.
Raw Evidence workspace_premium PRO
Full Lab Evidence
EXPLAIN plans, OOM kernel logs, benchmark raw output, and negative-control captures are available to Pro members.