When pg_wal keeps growing, identify whether a replication slot is retaining WAL for a consumer that is no longer advancing. Record the slot's owner, type, required position and current usability before deciding to restore the consumer, provide capacity or deliberately reinitialise it. Dropping an unfamiliar slot to recover space can destroy the consumer's continuation path.1, 2
This guide uses PostgreSQL 18. Some columns and settings differ on older releases. It provides read-only examples and decision boundaries; no slot was dropped, advanced or recreated, and no checkpoint or replication test was run.
A slot is a retention promise
A replication slot records information needed by its consumer. Its restart_lsn is the oldest WAL position that may still be required, subject to the configured retention limit. A logical slot also has confirmed_flush_lsn, the position through which its consumer has acknowledged receipt; that field is null for a physical slot.1
Those positions are not interchangeable. A consumer's acknowledged position does not automatically identify the oldest WAL PostgreSQL can discard for that slot. Use the documented fields for the question being asked rather than choosing whichever number looks most recent.
An inactive slot can be intentional during maintenance, or it can belong to a retired consumer. The database cannot infer the business meaning from inactivity alone. The operational inventory must connect slot name to a physical standby, logical subscription or external change-data consumer and to its responsible owner.
Slots can also retain row/catalog horizons through their xmin and catalog_xmin fields.1 This article focuses on WAL storage, but a complete incident assessment should note those fields when vacuum or catalogue retention is also affected.
Separate slot retention from other WAL needs
Record local WAL usage, filesystem reserve and the current generation rate through existing monitoring. Then check archival health and other documented retention requirements. A large WAL directory is a symptom, not proof that one particular slot caused all of it.
Do not confuse max_wal_size with an unconditional filesystem cap. The slot view explicitly describes an extended state in which files remain retained beyond that value.1 Capacity planning must include the retention obligations that can extend the amount kept.
In particular, extended can reflect retention by either a replication slot or wal_keep_size; it does not attribute every retained byte to the selected slot.1
Likewise, a byte distance between WAL positions is not an exact measurement of unique physical disk space owned by one slot. Several slots can require overlapping ranges, and segment allocation and other consumers affect the directory. Use the position gap to understand dependency and growth, then verify actual storage separately.
Inspect PostgreSQL 18 slot state
Use an existing authorised database diagnostic role. The following SELECT reads documented view fields and does not contact a consumer or alter its state. It is untested:
SELECT slot_name,
slot_type,
database,
active,
active_pid,
restart_lsn,
confirmed_flush_lsn,
wal_status,
safe_wal_size,
inactive_since,
invalidation_reason,
synced
FROM pg_replication_slots;
Record which server supplied the result and whether it is the primary or a standby. In PostgreSQL 18, synchronised logical slots on a hot standby have special behaviour: a slot marked synced cannot simply be used for decoding or manually dropped there.1 Do not apply a primary-side cleanup assumption to that state.
Match active_pid to the relevant connection evidence where authorised, but do not treat active = true as proof of useful throughput. A connected consumer may make no meaningful progress. Compare positions and consumer logs across a bounded interval.
Interpret usability before choosing a remedy
The PostgreSQL 18 reference defines these WAL states:1
wal_status |
Operational meaning |
|---|---|
reserved |
Required files remain within the normal max_wal_size range. |
extended |
Required files remain retained beyond that range. |
unreserved |
The slot no longer retains the required files; some are due for removal at a checkpoint, although the state can change again. |
lost |
The slot is no longer usable. |
Read invalidation_reason where present. In PostgreSQL 18 it can distinguish removed WAL from other invalidation causes, including conditions specific to logical slots and the configured idle timeout.1
safe_wal_size estimates how many additional WAL bytes can be written before the slot is at risk of becoming lost under the configured limit. A null value is not “zero bytes safe”: it can mean the slot is already lost or that max_slot_wal_keep_size is unlimited.1
These fields identify a state at capture time, not a guarantee that the consumer can finish catching up. Its downstream storage, processing rate and transaction handling still need investigation.
Find the consumer's reason for falling behind
Ask the owner to correlate the slot with consumer-side progress and errors. Distinguish a disconnected consumer from one that is receiving but not durably processing, and distinguish a planned pause from a failed deployment or retired integration.
For a physical standby, investigate its supported replication/recovery state. For a logical consumer, establish its acknowledged position, destination consistency and restart contract. Do not assume that recreating a connection or reusing the same slot name preserves an earlier data boundary.
Keep external consumer details scoped to their documentation. A connector can acknowledge work at a stage different from final business application. The slot's position is database evidence, not an automatic guarantee that a downstream report or service is correct.
Record a realistic recovery rate from measured evidence. If incoming WAL is generated faster than the consumer can process it, merely reconnecting may not reduce the backlog. The owner needs a capacity, workload or consumer-performance decision before local storage runs out.
Understand retention-limit trade-offs
For PostgreSQL 18, max_slot_wal_keep_size = -1 allows unlimited WAL retention by slots. A configured limit is enforced in relation to checkpoints and can lead to removal of WAL the consumer still needs.2 It protects against one form of unbounded retention by accepting a possible loss of the consumer's continuation path.
Do not lower that value as a cosmetic disk-space fix without an agreed reinitialisation plan. Raising it likewise does not create filesystem capacity. Evaluate the consumer's allowable outage, WAL generation and available reserve together.
PostgreSQL 18 also documents idle_replication_slot_timeout, disabled by default with zero. Invalidation happens during checkpoint processing and has exclusions described in the reference.2 It is not an exact wall-clock deletion timer, nor a substitute for an owner-maintained inventory. This article does not recommend enabling it or forcing a checkpoint during an incident.
Select one supported recovery path
If the slot remains usable and the consumer can catch up, repair the consumer's root cause and monitor actual position movement while preserving sufficient reserve. If legitimate backlog exceeds current capacity, plan supported capacity or workload containment with the service owner.
If the consumer is permanently retired, obtain explicit confirmation of retirement and of any data-retention obligations before a DBA removes the slot through the supported procedure. An unused-looking name is not sufficient evidence.
If the slot is lost or required WAL is gone, agree a supported reinitialisation or resnapshot workflow with the consumer owner. Document the new data boundary and how duplicates, omissions and downstream state will be reconciled. Do not skip WAL or manually remove local files to make the status appear healthy.
No destructive SQL or filesystem command is supplied. Slot deletion, advancement and recreation are data-continuity decisions, not routine read-only diagnostics.
Verify the whole path
Acceptance needs sustained consumer progress, a usable slot, storage growth within reserve and correct downstream data. A reduction in pg_wal after invalidating a slot is not proof of successful replication recovery.
Use an authorised disposable environment to test the intended pause, limit and reinitialisation behaviour with synthetic records. Include failures around acknowledgement so the consumer's actual delivery semantics are understood. No such laboratory validation is claimed here.
Preserve the old settings and evidence before an approved change, but be precise about rollback limits: returning a retention limit cannot recreate WAL already removed. Restoring continuity may require a new baseline rather than a setting reversal.
Learning notes
- A slot belongs to a consumer and preserves a specific continuation requirement.
- Connection activity and useful progress are different observations.
- Limiting retained WAL trades storage exposure against possible consumer reinitialisation.
Acceptance checklist
- [ ] Each retained slot has an identified consumer and continuation requirement.
- [ ] Slot state, position progress, other WAL retention and filesystem reserve are distinguished.
- [ ] The chosen recovery path preserves or explicitly rebuilds consumer continuity.
- [ ] Sustained progress and downstream correctness are verified; removed WAL is not assumed recoverable by reverting settings.
References
- PostgreSQL: Documentation: 18: 53.20. pg_replication_slots. Accessed 2026-11-01.
- PostgreSQL: Documentation: 18: 19.6. Replication. Accessed 2026-11-01.