Scenario
The DBA receives a disk usage alert at 6 AM. The pg_wal directory has grown from its normal 1 GB to 40 GB overnight. The database is running fine — no errors. A check reveals a logical replication slot was created 3 days ago for a new subscriber that was never actually deployed. The slot is inactive (active = false) and has been holding all WAL generated since it was created.
How to Identify
Conditions:
pg_wal directory much larger than expected
pg_replication_slots shows slot with active = false and low restart_lsn
wal_status = 'reserved' — WAL is being held for the slot
pg_stat_archiver shows archiving failing (secondary cause)
wal_keep_size set very high
Analysis Steps
-- Check pg_wal size:
SELECT pg_size_pretty(sum(size)) AS wal_size, count(*) AS wal_files
FROM pg_ls_waldir();
-- Find slots holding WAL:
SELECT
slot_name, slot_type, active, wal_status,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS held_wal
FROM pg_replication_slots
ORDER BY pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) DESC NULLS LAST;
-- Check wal_keep_size (extra WAL retained beyond what slots need):
SHOW wal_keep_size;
SHOW max_wal_size;
-- Check archiver status (failing archive also retains WAL):
SELECT archived_count, failed_count, last_failed_wal, last_archived_wal
FROM pg_stat_archiver;
-- Calculate: how much WAL is held by each cause
SELECT
current_setting('wal_keep_size') AS wal_keep_size,
pg_size_pretty(sum(size)) AS total_pg_wal_size
FROM pg_ls_waldir();
Pitfalls
- Inactive replication slots (
active = false) hold WAL indefinitely until the slot is consumed or dropped. WAL accumulates with no size limit unless max_slot_wal_keep_size is set.
- Dropping a slot immediately allows PostgreSQL to recycle WAL — but the slot’s subscriber will need to do a full table resync since the slot’s position is lost.
wal_keep_size retains WAL regardless of slots — both settings add to WAL retention.
- Never delete files directly from
pg_wal/ — PostgreSQL manages this directory exclusively.
max_slot_wal_keep_size (PG 13+) automatically invalidates slots that exceed their WAL budget, preventing unbounded growth.
Resolution Approach
Drop the inactive slot to immediately release held WAL. Set max_slot_wal_keep_size to prevent recurrence. Review wal_keep_size and reduce if it’s unnecessarily large.