What a slot does
Postgres writes every change to its write-ahead log (WAL), and normally recycles old WAL once a checkpoint no longer needs it. A reader that streams changes needs the server to wait for it. A slot is that promise. In the documentation’s words, a logical slot “represents a stream of changes that can be replayed to a client in the order they were made on the origin server”.1
Two properties follow:
- It outlives the connection. Slots persist independently of the connection using them and are crash-safe.1 A reader can disconnect, restart, and carry on from where it stopped, with nothing missed.
- One reader at a time. Only one receiver may consume changes from a slot at any given time.1 Two consumers need two slots.
The cost: WAL that can’t be removed
A slot keeps what its reader hasn’t consumed, whether or not anything is connected. The documentation is blunt: slots “will prevent removal of required resources even when there is no connection using them”, neither the WAL nor the catalog rows a slot needs can be removed by VACUUM, and in extreme cases this could cause the database to shut down to prevent transaction ID wraparound. Its advice is to drop a slot that is no longer required.1
The example shows how quickly it adds up. Nothing was reading audit_slot, so after one 200,000-row insert it was holding 25 MB of WAL. A slot left behind by a tool you stopped using keeps growing like that until the disk fills.
Keeping slots safe
- Cap the WAL a slot may hold.
max_slot_wal_keep_sizelimits how much WAL slots may retain. Its default, -1, lets them retain an unlimited amount.3 Past the cap, a reader that falls too far behind may not be able to continue, which is better than a full disk. - Expire idle slots. PostgreSQL 18 adds
idle_replication_slot_timeout, which invalidates slots that have been inactive for longer than the limit. It is off (0) by default.3 - Watch them.
pg_replication_slotsshows each slot, whether it is active, itswal_status, and itsrestart_lsn, from which you can compute how much WAL it holds, as in the example. - Count them.
max_replication_slotscaps how many slots the server supports; the default is 10.3 - Drop what you don’t use, with
pg_drop_replication_slot.
Why audits use one
An audit that reads the change stream must not miss a transaction because its reader restarted. A slot gives exactly that: every committed change, in commit order, from the reader’s last position. That is what lets a reader say “these are all the rows this transaction changed” rather than “these are the rows we happened to see”.