A healthcare platform running Debezium CDC on PostgreSQL had a recurring nightmare: every primary failover caused their CDC pipeline to lose position and require a full re-snapshot of their 2TB patient events table. The re-snapshot took 6 hours and blocked all CDC consumers during that time. After upgrading to PostgreSQL 17 and switching to failover-enabled replication slots, their next planned failover completed in 90 seconds with zero CDC pipeline disruption.
PostgreSQL 17 ships two major logical replication improvements: failover slots that survive primary switchover, and row/column filtering for selective replication. This guide covers both.
- Logical replication failover slots in PG17 survive physical replication failover — no more full re-snapshots after HA events.
- Row filtering allows publishing only rows matching a WHERE clause — reduce replication traffic and consumer load.
- Column filtering publishes only specific columns — useful for sensitive data exclusion and bandwidth reduction.
- Failover slots require
sync_replication_slots = onon all standbys.
The Slot Failover Problem
Before PostgreSQL 17, logical replication slots existed only on the primary. When a standby was promoted:
- The slot was gone — it existed only on the old primary
- The subscriber (Debezium, pglogical) lost its WAL position
- Full re-snapshot was required to restart the pipeline
- For large tables, this meant hours of downtime for downstream consumers
Creating Failover Slots in PostgreSQL 17
-- Enable slot synchronization on the primary
ALTER SYSTEM SET sync_replication_slots = on;
SELECT pg_reload_conf();
-- Create a logical replication slot with failover enabled
SELECT pg_create_logical_replication_slot(
'cdc_orders_pipeline', -- slot name
'pgoutput', -- plugin
false, -- not temporary
true -- failover = true (new in PG17)
);
-- Verify the slot is synced to standbys
SELECT slot_name, slot_type, failover, confirmed_flush_lsn,
pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn) AS lag_bytes
FROM pg_replication_slots WHERE failover = true;Failover slots only work with physical streaming replication standbys — not with logical replicas. Ensure primary_slot_name is configured on standbys for full synchronization.
-- On each standby: verify slot is synchronized
SELECT slot_name, synced, failover, confirmed_flush_lsn
FROM pg_replication_slots WHERE failover = true;Row Filtering in Publications
PostgreSQL 17 allows publishing only rows matching a WHERE clause, dramatically reducing replication volume for tables with high write rates but where subscribers only need a subset of rows:
-- Publish only completed orders (not pending/processing)
CREATE PUBLICATION orders_completed_pub FOR TABLE orders
WHERE (status = 'completed' AND total_amount > 0);
-- Publish only recent events (last 90 days rolling)
CREATE PUBLICATION recent_events_pub FOR TABLE events
WHERE (created_at > now() - INTERVAL '90 days');
-- Alter existing publication to add row filter
ALTER PUBLICATION orders_pub FOR TABLE orders
WHERE (region = 'US' AND status != 'cancelled');Row filters are evaluated on the primary before data is sent to subscribers. For tables where 80% of rows are irrelevant to downstream consumers, row filtering can reduce replication WAL traffic by 60-80%.
Column Filtering in Publications
-- Publish only non-PII columns
CREATE PUBLICATION orders_analytics_pub FOR TABLE orders
(id, product_id, quantity, total_amount, status, created_at);
-- Excludes: customer_email, shipping_address, payment_method
-- Combine row and column filtering
CREATE PUBLICATION orders_region_pub FOR TABLE orders
(id, region, total_amount, status)
WHERE (region IN ('US', 'EU'));Monitoring Logical Replication Health
-- Check replication slot lag (catch up before failover)
SELECT slot_name, pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn) AS lag_bytes,
failover, active
FROM pg_replication_slots WHERE slot_type = 'logical';
-- Check subscription status on subscriber
SELECT subname, subenabled, subpublications,
pg_wal_lsn_diff(latest_end_lsn, received_lsn) AS pending_bytes
FROM pg_stat_subscription;
-- View worker stats
SELECT subname, worker_type, last_msg_receipt_time,
latest_end_lsn, last_msg_send_time
FROM pg_stat_subscription_stats;- Enable
sync_replication_slots = onand create slots withfailover = truebefore your next HA event — not after. - Row filtering reduces replication volume and subscriber processing load — apply it to any table where consumers only need a subset of rows.
- Column filtering enables PII exclusion at the replication layer without application changes.
- Monitor slot lag continuously — a lagging slot accumulates WAL on the primary and can cause disk exhaustion.
Working with JusDB on PostgreSQL Replication
JusDB designs logical replication pipelines for CDC, analytics offloading, and cross-region data distribution. We have built Debezium pipelines on PostgreSQL 17 failover slots that survived planned HA events with zero re-snapshot requirements.