Both Debezium and RisingWave work with Aurora PostgreSQL, but Aurora adds constraints that vanilla PostgreSQL does not have: logical replication requires a custom parameter group, replication slots are a limited resource, and connection handling differs between Aurora writer and reader instances. This article walks through the setup for both tools, with attention to the gotchas that catch teams off guard.
Aurora PostgreSQL CDC Prerequisites
Aurora PostgreSQL uses logical replication for CDC, which requires wal_level=logical. Unlike self-managed PostgreSQL where you edit postgresql.conf, on Aurora you set this through a custom parameter group.
Step 1: Create or modify a cluster parameter group.
In the AWS Console, navigate to RDS → Parameter Groups → Create Parameter Group. Select the Aurora PostgreSQL family that matches your cluster version (e.g., aurora-postgresql15). Cluster type: Cluster.
Set the following parameter:
rds.logical_replication = 1
Setting rds.logical_replication = 1 automatically sets wal_level = logical and max_wal_senders to a value sufficient for replication.
Step 2: Apply the parameter group to your Aurora cluster.
In the cluster settings, update the DB cluster parameter group. Apply immediately or during the next maintenance window. A cluster restart is required for the rds.logical_replication change to take effect.
Step 3: Create a replication user.
CREATE ROLE replication_user WITH
REPLICATION
LOGIN
PASSWORD 'strong-password-here';
GRANT SELECT ON ALL TABLES IN SCHEMA public TO replication_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO replication_user;
Step 4: Update the security group.
The CDC tool (Debezium or RisingWave) must reach Aurora's writer instance on port 5432. Add an inbound rule for the source IP range. CDC reads from the writer — Aurora reader instances do not expose logical replication.
Debezium on Aurora PostgreSQL
Debezium's PostgreSQL connector uses the pgoutput plugin, which is available by default on Aurora PostgreSQL 10+. You do not need to install the wal2json or decoderbufs plugins.
Connector configuration:
{
"name": "aurora-cdc-connector",
"config": {
"connector.class": "io.debezium.connector.postgresql.PostgresConnector",
"database.hostname": "my-cluster.cluster-xxxxxxxxxxxx.us-east-1.rds.amazonaws.com",
"database.port": "5432",
"database.user": "replication_user",
"database.password": "strong-password-here",
"database.dbname": "mydb",
"topic.prefix": "aurora",
"plugin.name": "pgoutput",
"publication.name": "dbz_publication",
"slot.name": "debezium_slot",
"table.include.list": "public.orders,public.customers",
"snapshot.mode": "initial",
"heartbeat.interval.ms": "10000"
}
}
What Debezium creates on Aurora:
When the connector starts, it creates a logical replication slot named debezium_slot and a publication named dbz_publication. Both persist in Aurora until explicitly dropped.
Verify slot creation:
SELECT slot_name, plugin, active, restart_lsn
FROM pg_replication_slots;
The heartbeat.interval.ms setting matters on Aurora. Without a heartbeat, an idle Debezium connector stops sending keepalive messages. Aurora may then consider the replication connection stale and terminate it. Set heartbeat to 10 seconds or less for long-running connectors.
RisingWave on Aurora PostgreSQL
RisingWave's setup is simpler. The CDC source is defined in SQL, and RisingWave manages the replication slot and publication automatically.
CREATE SOURCE aurora_source
WITH (
connector = 'postgres-cdc',
hostname = 'my-cluster.cluster-xxxxxxxxxxxx.us-east-1.rds.amazonaws.com',
port = '5432',
username = 'replication_user',
password = 'strong-password-here',
database.name = 'mydb',
slot.name = 'risingwave_slot'
);
CREATE TABLE orders (
id BIGINT,
customer_id BIGINT,
product_id INT,
quantity INT,
amount DECIMAL(10,2),
status VARCHAR,
created_at TIMESTAMPTZ,
PRIMARY KEY (id)
) FROM aurora_source TABLE 'public.orders';
CREATE TABLE customers (
id BIGINT,
email VARCHAR,
region VARCHAR,
created_at TIMESTAMPTZ,
PRIMARY KEY (id)
) FROM aurora_source TABLE 'public.customers';
Now build real-time views over the CDC data:
CREATE MATERIALIZED VIEW order_summary AS
SELECT
c.region,
DATE_TRUNC('day', o.created_at) AS order_date,
COUNT(*) AS order_count,
SUM(o.amount) AS total_revenue
FROM orders o
JOIN customers c ON o.customer_id = c.id
WHERE o.status != 'cancelled'
GROUP BY c.region, DATE_TRUNC('day', o.created_at);
Aurora-Specific Gotchas
Replication slot limits. Aurora has a default limit on concurrent replication slots, typically 10. Each Debezium connector uses one slot. RisingWave uses one slot per source. If you run multiple Debezium connectors and RisingWave against the same Aurora cluster, plan your slot budget.
Check current slot usage:
SELECT count(*) FROM pg_replication_slots;
Increase the limit (up to Aurora's maximum) by adjusting max_replication_slots in the parameter group.
Inactive slot bloat. Aurora does not automatically remove replication slots when the consumer disconnects. An inactive slot holds WAL segments indefinitely, which causes storage to grow and eventually the primary to stall. Monitor inactive slots:
SELECT slot_name, active, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal
FROM pg_replication_slots
ORDER BY retained_wal DESC;
Drop stale slots explicitly:
SELECT pg_drop_replication_slot('old_slot_name');
Writer-only connections. CDC logical replication only works against the Aurora writer instance. Use the cluster endpoint (not the reader endpoint) in your connector configuration. If Aurora fails over, the writer endpoint automatically points to the new primary, and both Debezium and RisingWave will reconnect and resume from the last processed LSN.
SSL requirement. Aurora PostgreSQL enforces SSL by default. Both Debezium and RisingWave support SSL connections. For Debezium, add:
"database.sslmode": "require"
RisingWave uses SSL automatically when connecting to AWS RDS/Aurora endpoints.
Setup Complexity Comparison
| Step | Debezium | RisingWave |
| Aurora parameter group | Required (same) | Required (same) |
| Replication user | Required (same) | Required (same) |
| Kafka + Kafka Connect | Required | Not required |
| Connector config | JSON over REST API | SQL DDL |
| Replication slot management | Manual (monitor and drop inactive) | Managed by RisingWave |
| Publication management | Manual | Automatic |
| Schema history | Kafka topic | Internal |
| Heartbeat config | Must be set manually | Handled automatically |
When Both Tools Work Well Together
If you run Debezium today on Aurora and want to add RisingWave for analytics without replacing the existing Debezium pipeline, both can coexist. They each consume a separate replication slot. The Aurora writer sends WAL to both.
Aurora PostgreSQL writer
├── replication slot: debezium_slot → Kafka → microservices
└── replication slot: risingwave_slot → RisingWave → dashboards
Each slot is independent. Changes in one do not affect the other.
FAQ
What Aurora PostgreSQL version is required?
Both Debezium and RisingWave require PostgreSQL 10+. Aurora PostgreSQL 3.x (compatible with PostgreSQL 15) is recommended for current deployments. The pgoutput plugin is available in Aurora PostgreSQL 10.7+.
Does a Multi-AZ Aurora setup require any different configuration? No. The cluster endpoint always points to the current writer. On failover, Aurora promotes a reader to writer. The endpoint resolves to the new writer within seconds. CDC tools reconnect and resume from the last confirmed LSN.
Can I use an Aurora read replica for CDC?
No. Logical replication and pg_replication_slots are only available on the writer instance. Read replicas do not expose logical decoding.
What happens to the replication slot during an Aurora maintenance window? Aurora applies minor version updates during the maintenance window. If the update requires a restart, CDC connections will drop and reconnect. Both Debezium and RisingWave handle reconnects and resume from the last processed LSN.
How do I monitor CDC lag on Aurora?
Query pg_replication_slots.confirmed_flush_lsn against pg_current_wal_lsn() to measure how far behind each slot is:
SELECT
slot_name,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn)) AS lag
FROM pg_replication_slots;

