Initializing Enclave...

How to Fix PostgreSQL 'could not resize shared memory segment: No space left on device' Error

Threat/Impact Level: CRITICAL | Exploitability/Downtime Risk: HIGH | Time to Fix: 10 mins

TL;DR

  • What broke: PostgreSQL cannot allocate or resize its shared memory segment — typically /dev/shm is too small, shared_buffers is too large, or the kernel's POSIX shm tmpfs is exhausted.
  • How to fix it: Increase the /dev/shm tmpfs mount size (Docker/Kubernetes) or reduce shared_buffers to fit within available shared memory, and align kernel shmmax/shmall parameters.
  • Use our Client-Side Sandbox below to paste your postgresql.conf or Docker Compose file and auto-generate the corrected configuration.

The Incident (What Does the Error Mean?)

Raw error from PostgreSQL logs:

FATAL: could not resize shared memory segment "/PostgreSQL.1234567890" to 1073741824 bytes:
No space left on device

PostgreSQL uses POSIX shared memory (a file under /dev/shm on Linux) to back its shared buffer pool. When the process tries to size that segment to match shared_buffers, the kernel rejects the ftruncate() call because the tmpfs mounted at /dev/shm has no remaining capacity. The postmaster exits immediately. Every connection dies. Your database is down.

This is most commonly triggered in:

  • Docker containers where /dev/shm defaults to a hard 64 MB limit regardless of host RAM.
  • Kubernetes pods without an explicit emptyDir medium Memory volume for /dev/shm.
  • Bare-metal/VM deployments where shared_buffers was increased without adjusting kernel.shmmax.

The Attack Vector / Blast Radius

This is a full database outage vector. The cascade:

  1. Postmaster fails to start (or crashes mid-operation on a live resize).
  2. All active transactions are rolled back. Autovacuum, WAL writer, background workers — all dead.
  3. Applications hit connection refused or pool exhaustion within seconds.
  4. If this occurs during a rolling deployment, both old and new replicas may fail simultaneously if they share the same misconfigured base image or Helm chart values.
  5. In RDS-like self-managed setups, automated failover to a replica does nothing — the replica has the same postgresql.conf and will fail identically.

Secondary risk: Operators who "fix" this by blindly setting huge_pages = off without addressing the underlying shm size will mask the error temporarily but degrade TLB performance under load, causing latency regressions at scale.


How to Fix It

Root Cause Identification

First, confirm the actual /dev/shm size and what PostgreSQL is requesting:

# Check current /dev/shm capacity
df -h /dev/shm

# Check what shared_buffers is set to
grep shared_buffers /etc/postgresql/*/main/postgresql.conf

# Check kernel shm limits (bare metal/VM)
sysctl kernel.shmmax kernel.shmall

Fix 1: Docker — Increase /dev/shm at Container Runtime

The default Docker /dev/shm is 64 MB. If shared_buffers = 1GB, this will always fail.

# docker run
- docker run postgres:16
+ docker run --shm-size=256m postgres:16

# docker-compose.yml
  services:
    postgres:
      image: postgres:16
-     # no shm_size set
+     shm_size: '256mb'

Fix 2: Kubernetes — Mount a Memory-Backed emptyDir for /dev/shm

  spec:
    containers:
      - name: postgres
        image: postgres:16
+       volumeMounts:
+         - name: dshm
+           mountPath: /dev/shm
+   volumes:
+     - name: dshm
+       emptyDir:
+         medium: Memory
+         sizeLimit: 256Mi

⚠️ sizeLimit counts against the pod's memory limit. Set resources.limits.memory accordingly or the pod will be OOMKilled.


Fix 3: Bare Metal / VM — Align shared_buffers with Kernel Shm Limits

# /etc/postgresql/16/main/postgresql.conf
- shared_buffers = 8GB
+ shared_buffers = 2GB   # Rule of thumb: 25% of total RAM, must be < kernel.shmmax

# /etc/sysctl.conf
- # kernel.shmmax not set (defaults to 33554432 = 32MB on some distros)
+ kernel.shmmax = 4294967296   # 4GB — must exceed shared_buffers in bytes
+ kernel.shmall = 1048576      # pages: shmmax / PAGE_SIZE (4096)

Apply without reboot:

sysctl -p
systemctl restart postgresql

Enterprise Best Practice

Do not hardcode shm sizes. Derive them from the instance's available memory using configuration management:

# Ansible task — postgresql.conf template
- shared_buffers: "1GB"
+ shared_buffers: "{{ (ansible_memtotal_mb * 0.25) | int }}MB"

# Helm values.yaml for postgres chart
  resources:
    limits:
-     memory: "4Gi"
+     memory: "4Gi"          # Set this first
  postgresqlSharedBuffers: "1GB"   # Must be < (memory limit - overhead)
+ shmSize: "1536Mi"               # 1.5x shared_buffers as safe headroom

💡 Tired of pasting proprietary configs into ChatGPT? Generic AI tools log your company's ARNs, DB strings, and private keys. StackEngine is a zero-backend, pure Client-Side WASM utility. Drop your failing config into the sandbox above. We redact your secrets locally in the browser and auto-generate the refactored code using your own API key.


Prevention in CI/CD

1. Checkov — Catch Missing shm_size in Docker Compose

Checkov has no built-in rule for shm_size, so add a custom policy:

# .checkov/custom_checks/postgres_shm.yaml
metadata:
  name: "PostgreSQL container must define shm_size"
  id: "CKV_CUSTOM_POSTGRES_SHM"
scope:
  - docker_compose
attribute: services.*.shm_size
operator: exists

Run in pipeline:

checkov -d . --external-checks-dir .checkov/custom_checks

2. OPA/Conftest — Validate Kubernetes Pod Spec

# policy/postgres_shm.rego
package main

deny[msg] {
  input.kind == "Deployment"
  container := input.spec.template.spec.containers[_]
  contains(container.image, "postgres")
  not shm_volume_mounted(input)
  msg := sprintf("Container '%v' uses postgres but has no Memory-backed emptyDir for /dev/shm", [container.name])
}

shm_volume_mounted(spec) {
  vol := spec.spec.template.spec.volumes[_]
  vol.emptyDir.medium == "Memory"
}
# In CI
conftest test k8s/postgres-deployment.yaml --policy policy/

3. Alerting — Catch It Before Full Crash

Add a Prometheus alert on shared memory pressure before PostgreSQL hard-fails:

# prometheus/alerts.yaml
- alert: PostgresSharedMemoryNearCapacity
  expr: |
    node_filesystem_avail_bytes{mountpoint="/dev/shm"} /
    node_filesystem_size_bytes{mountpoint="/dev/shm"} < 0.15
  for: 2m
  labels:
    severity: warning
  annotations:
    summary: "/dev/shm is over 85% full — PostgreSQL crash imminent"

Related Diagnostics

"Part of the Performance Utility Matrix."

View all 219 Performance Tools →