Replication Slots
Replication slots tell the primary to retain WAL until a consumer confirms receipt. They prevent standbys and logical subscribers from falling off the WAL timeline.
Recipe
Create a physical slot for each standby; drop orphans promptly.
-- Physical slot for a streaming standby
SELECT pg_create_physical_replication_slot('standby1_slot');
-- Inspect lag and retained WAL
SELECT slot_name, slot_type, active, restart_lsn,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained
FROM pg_replication_slots;# Drop an unused slot (after confirming standby is decommissioned)
psql -h primary.db.internal -U postgres -c \
"SELECT pg_drop_replication_slot('old_standby_slot');"When to reach for this: Any long-lived standby, logical subscriber, or backup tool that must not lose WAL.
Working Example
Create slot during base backup, monitor inactive slots:
# pg_basebackup with slot creation
pg_basebackup -h primary.db.internal -U replicator \
-D /var/lib/postgresql/18/main -Fp -Xs -P -R \
-C -S standby1_slot-- Alert query: inactive slot retaining WAL
SELECT slot_name, active,
pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) AS bytes_retained
FROM pg_replication_slots
WHERE NOT active
AND pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) > 1073741824; -- 1 GiBWhat this demonstrates:
- Physical slots tie WAL retention to a named consumer.
active = falsewith largebytes_retainedsignals a dead consumer filling disk.pg_basebackup -C -Spairs initial clone with slot creation in one step.
Deep Dive
Slot Types
| Type | Created by | Consumer |
|---|---|---|
| Physical | pg_create_physical_replication_slot, pg_basebackup -C | Streaming standby, pg_receivewal |
| Logical | pg_create_logical_replication_slot | Logical replication subscriber, CDC tools |
Key Catalog Columns
| Column | Meaning |
|---|---|
restart_lsn | Earliest WAL still needed by slot |
confirmed_flush_lsn | Logical subscriber acknowledged position |
active | Consumer currently connected |
wal_status | reserved, extended, unreserved, lost (PostgreSQL 18) |
Disk Risk
Slots override wal_keep_size and can prevent WAL recycling. Combine:
- Per-slot monitoring alerts
max_slot_wal_keep_sizeas a safety valve (PostgreSQL 13+)- Runbook to drop abandoned slots after change tickets
Gotchas
- Inactive slot after failed standby rebuild - Primary disk fills with retained WAL. Fix: Drop slot or reconnect consumer within SLA.
- Logical slot without subscriber - Same disk pressure as physical orphans. Fix: Track slots in config management; alert on
active = false. - No
max_slot_wal_keep_size- One bad slot can exhaust disk. Fix: Set a bounded retention policy and page onwal_status = 'lost'. - Duplicate slot names - Creation fails or wrong consumer binds. Fix: Name slots after hostname or Patroni member name.
- Backup slot + aggressive archiving - Archiver and slot both retain WAL; plan total disk headroom. Fix: Size WAL volume for worst-case lag plus archive failures.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
wal_keep_size only | Ephemeral test standbys | Production standbys that may disconnect |
| Archive + restore | DR without continuous streaming | You need hot standby failover |
| Temporary slot during catch-up | One-time reseed | Long-term retention without monitoring |
FAQs
One slot per standby?
Yes for production physical standbys. Logical subscribers need their own logical slots.
Can slots exist on standbys?
Physical standbys do not create sender slots; slots live on the primary (or upstream logical publisher).
What is wal_status = lost?
The slot required WAL that was already removed. Recreate consumer from a fresh base backup.
Does Patroni manage slots?
Patroni 3.x can create and synchronize permanent replication slots across the cluster. Verify slots section in Patroni YAML.
max_slot_wal_keep_size vs dropping slots?
max_slot_wal_keep_size caps retention but may invalidate lagging consumers. Prefer alerting and operational slot hygiene.
Related
- Streaming Replication Basics - standby setup
- Replication Monitoring - lag alerts
- Logical Replication Basics - logical slots
- Archive Mode & archive_command - WAL shipping
Stack versions: This page was written for PostgreSQL 18.4 (stable 18, maintenance 17), pgvector 0.8+, PgBouncer 1.x, Patroni 3.x, and PostGIS 3.5+.