PostgreSQL 19 brings an interesting improvement for DBAs working with logical decoding and logical replication: the introduction of effective_wal_level.
It addresses a practical operational challenge that PostgreSQL DBAs have traditionally faced when enabling logical decoding on a server running with wal_level = replica.
Consider a PostgreSQL server configured with:
SHOW wal_level;
wal_level
-----------
replicaThis is sufficient for physical streaming replication. But if we later need logical decoding, for example for CDC, logical replication, or a migration pipeline, we need wal_level = logical.
Before PostgreSQL 19, changing wal_level from replica to logical required a PostgreSQL restart. So a simple requirement such as "enable logical decoding" could turn into:
Change wal_level
↓
Restart PostgreSQL
↓
Start logical decodingFor production environments, that restart may require a maintenance window.
PostgreSQL 19 introduces effective_wal_level. The important concept is the separation between the configured WAL level and the effective WAL level.
For example, SHOW wal_level; can still return replica, while SHOW effective_wal_level; returns logical. So PostgreSQL can have:
wal_level = replica
effective_wal_level = logicalThe configured wal_level has not changed. Instead, PostgreSQL dynamically uses the higher effective WAL level when logical decoding is required.
The concept is straightforward:
wal_level = replica
|
v
Is logical decoding needed?
/ \
No Yes
| |
v v
replica logical
| |
+-------+--------+
|
v
effective_wal_levelWhen a valid logical replication slot requires logical decoding, PostgreSQL can automatically operate with effective_wal_level = logical without changing the configured wal_level = replica, and without requiring a restart just for this transition.
| Before PostgreSQL 19 | PostgreSQL 19 (starting from wal_level = replica) | |
|---|---|---|
| How logical decoding is enabled | Set wal_level = logical in the config | Create a logical replication slot |
| Restart needed for this change | Yes | No |
Configured wal_level afterwards | logical | Still replica |
effective_wal_level | Not applicable | logical while a valid logical slot exists |
| When the last logical slot is dropped or invalidated | Stays logical until you change the config and restart | Returns to replica, asynchronously |
Initially:
SELECT
current_setting('wal_level') AS wal_level,
current_setting('effective_wal_level') AS effective_wal_level;
wal_level | effective_wal_level
-----------+---------------------
replica | replicaNow create a logical replication slot:
SELECT pg_create_logical_replication_slot(
'demo_slot',
'pgoutput'
);Check again:
SELECT
current_setting('wal_level') AS wal_level,
current_setting('effective_wal_level') AS effective_wal_level;
wal_level | effective_wal_level
-----------+---------------------
replica | logicalThe important point is that wal_level remains replica. Only the effective WAL level has changed. When the last valid logical slot is removed, PostgreSQL can eventually return the effective level to replica.
This is particularly useful for environments using:
Previously, enabling logical decoding involved a restart. With PostgreSQL 19, the path is much shorter:
wal_level = replica
↓
Logical slot created
↓
effective_wal_level = logical
↓
Logical decodingThis makes the transition much more dynamic and avoids a restart solely for changing the effective WAL level.
Planning to build a CDC or data migration pipeline on PostgreSQL? See how Mafiree’s Xstreami can help you move your data reliably and efficiently.
Explore Mafiree’s XstreamiThe easiest way to remember the difference:
| Setting | Meaning |
|---|---|
wal_level | Configured WAL level |
effective_wal_level | WAL level PostgreSQL is effectively operating with |
Quick tip: when troubleshooting logical decoding in PostgreSQL 19, don't look only at SHOW wal_level;. Also run SHOW effective_wal_level;, or query both together with current_setting() as shown above.
| Check | Why it matters |
|---|---|
| Standby servers | Logical slots on a standby are invalidated if the primary's effective_wal_level drops below logical. |
Tools that read wal_level directly | A tool that validates the configured value may not recognize the effective one. Test your CDC tool first. |
wal_level = minimal | The documented behavior applies when wal_level = replica. The PostgreSQL docs don't describe it for minimal, so don't assume it applies. |
Timing of the drop back to replica | It's asynchronous, so don't expect an instant change. |
Not sure whether your setup is ready for dynamic logical decoding? Talk to a Mafiree PostgreSQL Expert about your replication and migration strategy.
Talk to a Mafiree PostgreSQL Experteffective_wal_level is a relatively small change in PostgreSQL 19, but it provides a useful operational improvement. PostgreSQL can keep wal_level = replica while dynamically using effective_wal_level = logical when logical decoding is actually required.
wal_level tells us what is configured, while effective_wal_level tells us what PostgreSQL is effectively using.
For PostgreSQL DBAs, this means one less restart-driven operation when logical decoding needs to be enabled dynamically.
Managing PostgreSQL in production involves much more than configuration changes: from high availability and replication to performance tuning, monitoring, migrations, backup and recovery, and 24/7 database support. At Mafiree, we provide database management and DBA support services across PostgreSQL and other database technologies, helping organizations manage their production database environments with the right operational expertise.
Miru IT Park, Vallankumaranvillai,
Nagercoil, Tamilnadu - 629 002.
Unit 303, Vanguard Rise,
5th Main, Konena Agrahara,
Old Airport Road, Bangalore - 560 017.
Call: +91 6383016411
Email: sales@mafiree.com