If your primary PostgreSQL server crashes, your logical replication normally breaks. The subscriber loses its slot, and you have to rebuild everything from scratch. PostgreSQL 18 fixes this problem with synchronized failover slots. In this guide, you will learn how to set up a complete PostgreSQL 18 logical replication failover.
Complete Setup Guide for PostgreSQL 18 Logical Replication Failover
Table of Contents
- What Is PostgreSQL 18 Logical Replication Failover
- Lab Architecture: Primary, Standby, and Subscriber
- Step 1: Install PostgreSQL 18 on All Three Nodes
- Step 2: Configure the Primary Server (Node A)
- Step 3: Build the Physical Standby (Node B)
- Step 4: Create the Publication on the Primary Node
- Step 5: Create the Subscription with Failover Enabled (Node C)
- Step 6: Verify the Failover Slots Are Synced to the Standby
- Step 7: Simulate the Failover
- Step 8: Point the Subscriber to the New Primary
- Step 9: Clean Up and Re-Point the Standby Chain
- Common Mistakes That Break Failover Slots
- Conclusion

What Is PostgreSQL 18 Logical Replication Failover
Logical replication lets you copy specific tables or databases to another server using a publication and a subscription. Before PostgreSQL 17, there was a big problem. If the primary server died, its logical replication slot died too. The subscriber had no way to know where to pick up on a new server.
PostgreSQL 17 introduced failover-ready logical slots. PostgreSQL 18 makes this feature more solid and reliable. With this failover mechanism, the primary copies its logical slots to a physical standby in the background. If the primary goes down and the standby gets promoted, the subscriber just switches to the new primary and keeps going. No need to re-copy data, and no broken pipeline.
This matters if you run production databases, where downtime means lost money. Also, if you cover high availability topics, you can check out the pgBackRest backups and recovery tutorial too, which covers backups and point-in-time recovery. This guide covers live failover for a running replication pipeline.
Lab Architecture: Primary, Standby, and Subscriber
To test PostgreSQL 18 logical replication failover properly, you need three separate servers or virtual machines:
- Node A (Primary): IP
10.0.0.1, runs the main database and the publication. - Node B (Standby): IP
10.0.0.2, a physical standby of Node A, using streaming replication, and it will hold the synced failover slots. - Node C (Subscriber): IP
10.0.0.3, a separate PostgreSQL 18 server that subscribes to the publication on Node A.
Note: All three nodes must run PostgreSQL 18, the latest stable release at the time of this guide. Mixing versions between primary and standby is not supported for physical replication.
You can use three PerLod VPS or dedicated server hosting for this lab. Keeping the nodes on separate machines is closer to a real production setup than testing everything on one laptop.
Step 1: Install PostgreSQL 18 on All Three Nodes
You must install PostgreSQL 18 on Node A, Node B, and Node C. This guide assumes you are using Ubuntu:
Check the version after installation:
You should see PostgreSQL 18.x. Make sure all three nodes report the same version before continuing.
Step 2: Configure the Primary Server (Node A)
You must open the main config file on Node A with your desired text editor:
Then, set the following values. These are required for both physical streaming replication and for synchronized failover slots to work:
The wal_level = logical setting is required for logical decoding. Without it, publications cannot exist. The synchronized_standby_slots setting tells the primary to wait until the named physical slot confirms it received the WAL before sending changes to logical subscribers. This is the setting that guarantees the standby never falls behind the subscriber.
Once you are done, open the access file to allow replication connections:
Add these lines and replace IPs with your real node addresses:
Save and close the file. Restart PostgreSQL so the settings apply:
Next, you must create a replication role and a role for the subscriber connection. Connect to the primary server as the postgres user:
Run these CREATE ROLE commands inside the psql prompt:
Step 3: Build the Physical Standby (Node B)
The standby must exist before we can sync failover slots to it. First, create a physical replication slot on the primary node for the standby to use:
This name, standby_1, matches the synchronized_standby_slots value we set earlier in Step 2.
Now on Node B, you must stop PostgreSQL and clear the data directory, then take a base backup from the primary:
The -S standby_1 flag tells pg_basebackup to use the existing physical slot, and -R writes the standby connection settings automatically into postgresql.auto.conf.
Then, edit the standby's config to enable logical failover slot sync. This is the key part for PostgreSQL 18 logical replication failover:
hot_standby_feedback must be on; otherwise the primary may remove rows the standby still needs. sync_replication_slots = on starts a background worker on the standby that pulls the logical failover slots from the primary automatically.
Check that primary_conninfo and primary_slot_name were set correctly by pg_basebackup:
You should see primary_slot_name = 'standby_1' in the output. If it is missing, you must add it manually:
Start the standby:
Confirm the standby is streaming:
Step 4: Create the Publication on the Primary Node
Back on Node A, use the command below to create a test table and a publication:
Step 5: Create the Subscription with Failover Enabled (Node C)
This is the step that turns a normal logical replication setup into a true failover-ready setup. On Node C, create the matching table first:
Now create the subscription and set failover = true:
The failover = true option marks the logical slot on the primary as eligible for syncing to the physical standby. Without this flag, the slot remains local to the primary and will not survive a promotion.
Check that the subscription is active and the initial table copy has finished:
subfailover should show t, and srsubstate should show r, meaning the table is fully synced and streaming.
Step 6: Verify the Failover Slots Are Synced to the Standby
This validation step is the most important part of PostgreSQL 18 logical replication failover. A slot that looks synced but is not truly ready will break your failover.
First, on the subscriber node (Node C), find which slots must exist on the standby:
Next, on the primary (Node A), you can get the full list of every failover-ready slot at once:
Finally, on the standby (Node B), confirm those slots exist and are ready:
If failover_ready shows t, the slot has been fully synced to the standby and is safe to use after promotion. If it shows f or the row is missing, wait a few seconds and run the query again; the slotsync worker syncs slots periodically, not instantly.
Also, you can force an immediate manual sync instead of waiting for the background worker by running this on the standby:
Step 7: Simulate the Failover
Now we want to test the real scenario. If the primary goes down, the subscriber must keep working from the new primary. This is the actual proof that PostgreSQL 18 logical replication failover works.
First, you must insert a row on the primary before the failover to confirm normal replication:
Check it arrived on the subscriber with:
Now stop the primary to simulate a crash:
Promote the standby (Node B) to become the new primary:
Or, you can do it from inside psql on the standby:
Wait a few seconds, then confirm Node B is no longer in recovery:
It should return f, meaning Node B is now a normal read-write primary.
Step 8: Point the Subscriber to the New Primary
The subscriber's connection string still points at the old primary's IP address. You must update it to point at Node B, which is now the primary:
There is no need to drop and recreate the subscription, and no need to create a new slot. Because the slot was already synced by sync_replication_slots in Step 3, it exists on Node B with the correct position already recorded.
Insert a new row on the new primary (Node B) to confirm replication continues:
Check the subscriber again:
If you see both rows, "Test Customer 1" and "Test Customer 2", the PostgreSQL 18 logical replication failover worked correctly. The subscription resumed from exactly where it left off, using the slot that was synchronized before the crash.
Step 9: Clean Up and Re-Point the Standby Chain
After a real failover, Node A is gone or needs to be rebuilt as a new standby of Node B. You must create a fresh physical replication slot for it, and set synchronized_standby_slots on Node B to use that slot's name.
This keeps your failover protection working for the next incident, instead of leaving Node B as a single point of failure.
Common Mistakes That Break Failover Slots
A few small mistakes cause most failures in these failover setups:
- Forgetting
failover = trueon the subscription, which leaves the slot local to the primary only. - Forgetting
hot_standby_feedback = onon the standby, which can cause the primary to remove data the standby still needs. - Not setting
primary_slot_nameon the standby, which stops slot sync from working at all. - Checking slot readiness once and assuming it stays ready, instead of re-checking
failover_readyright before the actual failover. - Mixing PostgreSQL versions between primary and standby, which is not supported.
Conclusion
PostgreSQL 18 logical replication failover solves the biggest problem in logical replication, which is losing your subscription when the primary fails. Turn on failover = true on the subscription, sync_replication_slots on the standby, and synchronized_standby_slots on the primary. Your logical slots now move to the standby automatically. When you promote the standby, the subscriber just needs a new connection string; no rebuild needed. Test this on real separate servers first, and always check failover_ready before you pull the plug on the primary.
We hope you enjoy this guide. For more detailed information, you can check the PostgreSQL Logical Replication Failover Docs.