Skip to main content
RunBook Academy

PostgreSQLXVII · Capacity, Maintenance and UpgradesMaintenance

Disk-full: distinguishing data, WAL, temp, archive and backup

Advanced⏱ ~35 min🧪 Lab requiredpsqldf

What you'll learn

  • Identify which filesystem filled, before acting
  • Recover a cluster whose pg_wal filesystem is full
  • Recognise why deleting WAL is the wrong response
  • Separate the filesystems so one failure does not become all of them

Prerequisites

Verified against PostgreSQL 18.x · PostgreSQL (comparison targets) 17.11, 16.15 · PostgreSQL (support calendar) 18, 17, 16, 15, 14 supported · pgBackRest 2.59.1 · PgBouncer 1.25.2 · Patroni 4.1.5 · Ubuntu (host baseline) 26.04 LTS · 2026-08-27

Not yet marked complete on this device.

“The disk is full” is five different incidents with five different responses. Establishing which filesystem filled is the first action, and it takes ten seconds.

Identify first

df -h \
  /var/lib/postgresql/18/main \
  /var/lib/postgresql/18/main/pg_wal \
  /var/lib/postgresql/18/main/base/pgsql_tmp \
  /archive \
  /backup \
  /var/log/postgresql
FilledSymptomResponse
pg_walPANIC, cluster down and will not restartGive it space. Never delete WAL
DataWrites fail; cluster survivesFree space, then find the growth
TempQueries fail with a temp-file errorLower work_mem, or fix the query
ArchiveArchiving fails; pg_wal starts growingFix the destination. Lesson XIII-05
BackupBackups fail silentlyRetention, and an alert
LogsLogging fails; may block backendsRotation. Lesson XVI-01

The archive row is the one that cascades: a full archive stops archiving, unarchived segments cannot be recycled, and pg_wal fills next. What looks like a WAL problem started somewhere else.

What a full pg_wal actually does

Data-loss riskthe filesystem reaching 100%
$ df -h /walspace
tmpfs            48M   48M     0 100% /walspace
Data-loss riskthe server log, verbatim
$ grep -iE 'PANIC|FATAL|recovery|shut' /tmp/full.log
PANIC:  could not write to file "pg_wal/xlogtemp.61": No space left on device
LOG:  database system was interrupted; last known up at 2026-08-27 23:31:00 UTC
FATAL:  the database system is in recovery mode
LOG:  database system was not properly shut down; automatic recovery in progress
FATAL:  could not write to file "pg_wal/xlogtemp.69": No space left on device
LOG:  shutting down due to startup process failure
LOG:  database system is shut down

The recovery

Destructivemoving pg_wal to a filesystem with room, keeping every segment
$ ls -la $PGDATA/pg_wal
du -sh /walspace/pg_wal

mkdir -p /var/lib/postgresql/walrescue
cp -a /walspace/pg_wal/. /var/lib/postgresql/walrescue/
rm -f $PGDATA/pg_wal
ln -s /var/lib/postgresql/walrescue $PGDATA/pg_wal
lrwxrwxrwx ... pg_wal -> /walspace/pg_wal
48M	/walspace/pg_wal

lrwxrwxrwx ... pg_wal -> /var/lib/postgresql/walrescue
Read-only / Safeand it comes back
$ pg_ctl -D $PGDATA start; SELECT count(*) FROM fill;
server started

LOG:  database system was not properly shut down; automatic recovery in progress
LOG:  redo starts at 0/17615F8
LOG:  redo done at 0/3FFFDE8 system usage: CPU: user: 0.02 s, system: 0.00 s, elapsed: 0.03 s
LOG:  checkpoint starting: end-of-recovery immediate wait
LOG:  checkpoint complete: wrote 5094 buffers (31.1%) ... distance=41594 kB
LOG:  database system is ready to accept connections

rows_recovered
----------------
        60000

Every committed row recovered, because no WAL was deleted.

The end-of-recovery checkpoint wrote 5,094 buffers — 31.1% of the pool — over a redo distance of 41,594 kB. That is the work that had accumulated and could not be written, now flushed.

Other ways to create space, in order of preference:

  1. Extend the filesystem. Best, if the storage allows it.
  2. Move pg_wal to another filesystem and symlink, as above.
  3. Delete something else on that filesystem — logs, an old backup.
  4. Fix what was retaining WAL, which is the actual cause: a failing archive, an abandoned slot, wal_keep_size. Lesson XII-03.

Step 4 is the only one that stops it recurring.

Prevention

Separate filesystems. pg_wal, data, and the archive on different volumes means one filling does not take the others with it. This is the single highest-value structural decision in this lesson.

Alert at 75% on pg_wal specifically, not on the data volume — they fill at completely different rates.

Bound what retains WAL. max_slot_wal_keep_size, from lesson XIV-06, converts an unbounded pg_wal into an invalidated slot, which is a task rather than an outage.

Watch pg_stat_archiver. A failing archive is a pg_wal problem that has not happened yet.

What to take from this

  • Identify which filesystem filled before doing anything. Five filesystems, five responses.
  • A full archive cascades into a full pg_wal. The symptom is not the cause.
  • Measured: a full pg_wal produced a PANIC, recovery then failed for the same reason, and the cluster would not start.
  • Never delete WAL segments, and pg_resetwal is not a disk-space tool.
  • The fix is space: extend, move and symlink, or delete something else. Then fix what was retaining WAL.
  • Measured: after moving pg_wal, all 60,000 committed rows recovered.
  • Separate filesystems, alert on pg_wal at 75%, and keep a ballast file.

Cross-course references

  • Linux for Production Sysadmins — Part XIV (Filesystems) and Part XVI (LVM) cover finding what actually filled and whether it can be grown in place, and Part LXXX (Common failure scenarios) covers the reflex responses that make this worse.
  • Ceph & Distributed Storage — Part LXIV (Nearfull, backfillfull and full) and Part LXV (Why full clusters are dangerous) cover the same failure where the storage system stops accepting writes for everyone.
  • Observability for Production Sysadmins — Part XVIII (Alerting rules) covers alerting on each filesystem separately, since the response differs per volume.

Quiz

Knowledge check · 6 questions

  1. Q1. A cluster whose pg_wal filesystem filled has PANICked and will not restart. What distinguishes this from a full data filesystem?

  2. Q2. pg_wal has filled. Which action recovers the cluster without losing data?

  3. Q3. Why is exhausting WAL space a PANIC rather than an ordinary error?

  4. Q4. Which measures reduce the risk or impact of a full pg_wal? Select all that apply.

  5. Q5. A full archive destination can cause pg_wal to fill even though nothing is wrong with the pg_wal filesystem itself.

  6. Q6. Walk through responding to a full pg_wal filesystem, and explain why deleting WAL is the wrong instinct.

Passing score: 75%. Answers are checked in this browser.