High Availability

PostgreSQL 17 Logical Replication: Failover Slots and Row Filtering

Logical replication in PostgreSQL has a critical gap: slots do not survive failover. PostgreSQL 17 finally fixes this with failover slots, plus adds row and column filtering for selective replication.

JusDB Team
June 10, 2025
8 min read
175 views

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.

TL;DR
  • 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 = on on all standbys.

The Slot Failover Problem

Before PostgreSQL 17, logical replication slots existed only on the primary. When a standby was promoted:

  1. The slot was gone — it existed only on the old primary
  2. The subscriber (Debezium, pglogical) lost its WAL position
  3. Full re-snapshot was required to restart the pipeline
  4. For large tables, this meant hours of downtime for downstream consumers

Creating Failover Slots in PostgreSQL 17

sql
-- 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;
Warning

Failover slots only work with physical streaming replication standbys — not with logical replicas. Ensure primary_slot_name is configured on standbys for full synchronization.

sql
-- 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:

sql
-- 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');
Tip

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

sql
-- 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

sql
-- 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;
Key Takeaways
  • Enable sync_replication_slots = on and create slots with failover = true before 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.

Explore JusDB PostgreSQL Consulting →  |  Talk to a DBA

Share this article

JusDB Team

Official JusDB content team