Sync PostgreSQL to MySQL
with real-time CDC.
Stream every INSERT, UPDATE, and DELETE from PostgreSQL to MySQL in sub-second latency — via logical replication, not polling. Automatic type mapping, PII masking, resumable.
rsync.ai subscribes to PostgreSQL logical replication (pgoutput plugin) and writes change events to MySQL as they happen. Takes an initial consistent snapshot first, then switches to streaming. Handles type mapping automatically: UUID→CHAR(36), JSONB→JSON, TIMESTAMPTZ→DATETIME. Works with self-hosted Postgres, RDS, Aurora, Cloud SQL, Supabase, and Neon as source; MySQL 5.7+, RDS, Aurora, Cloud SQL, Azure as destination.
- Real-time CDC via logical replication — sub-second latency, no polling
- Automatic type mapping: UUID, JSONB, TIMESTAMPTZ, arrays
- Initial snapshot + live streaming — consistent from day one
- Self-hosted, source-available under Elastic License 2.0
How to sync PostgreSQL to MySQL — 5 steps
From enabling logical replication to rows streaming into MySQL.
- 1
Enable logical replication on PostgreSQL
Set `wal_level=logical` in postgresql.conf (or via the RDS parameter group). Set `max_replication_slots` to at least 2 and `max_wal_senders` to at least 2. Then create a replication slot and a publication: `SELECT pg_create_logical_replication_slot('rsync_slot', 'pgoutput');` and `CREATE PUBLICATION rsync_pub FOR ALL TABLES;`. Restart Postgres if you changed wal_level.
wal_level=logical · pgoutput plugin - 2
Connect PostgreSQL in rsync.ai
Provide host, port (default 5432), user, password, database name, the replication slot name (`rsync_slot`), and the publication name (`rsync_pub`). The user needs REPLICATION privilege: `ALTER ROLE your_user REPLICATION LOGIN;`. rsync.ai supports self-hosted Postgres 10+, Amazon RDS, Aurora PostgreSQL, Google Cloud SQL, Supabase, and Neon.
host · port · user · password · database · slot · publication - 3
Connect MySQL as the destination
Provide host, port (default 3306), user, and password. The user needs CREATE, ALTER, INSERT, UPDATE, DELETE on the target database. rsync.ai supports MySQL 5.7+, MySQL 8.0+, MariaDB 10.3+, Amazon RDS for MySQL, Amazon Aurora MySQL, Google Cloud SQL for MySQL, and Azure Database for MySQL. SSL and SSH tunnel are both supported.
mysql://user:pass@host:3306/db — MySQL 5.7+ / RDS / Aurora / Cloud SQL - 4
Describe the sync in plain English
Type what you want: 'Replicate all tables from the public schema of my Postgres database to MySQL in real time.' rsync.ai reads the publication's table list from Postgres and proposes a target MySQL database with the same table names. You can rename tables or restrict to a subset at this step.
No SQL · No YAML · No DAGs - 5
Approve DDL and start streaming
rsync.ai shows the proposed MySQL CREATE TABLE statements with automatic type mappings applied — UUID→CHAR(36), JSONB→JSON, TIMESTAMPTZ→DATETIME, arrays→JSON. Review and adjust any column. Approve, and rsync.ai takes an initial snapshot then switches to streaming CDC. Each change (INSERT/UPDATE/DELETE) arrives in MySQL in sub-second latency.
Initial snapshot → live CDC stream · sub-second latency
PostgreSQL → MySQL type mapping
Default mapping rsync.ai proposes. Override any column type before approving.
| PostgreSQL column (type) | MySQL column (type) | Notes | |
|---|---|---|---|
| users (id UUID, email TEXT, created_at TIMESTAMPTZ) | users (id CHAR(36), email TEXT, created_at DATETIME) | UUID→CHAR(36), TIMESTAMPTZ→DATETIME | |
| orders (id UUID, user_id UUID, total NUMERIC(10,2), status TEXT) | orders (id CHAR(36), user_id CHAR(36), total DECIMAL(10,2), status VARCHAR(255)) | NUMERIC→DECIMAL, TEXT→VARCHAR(255) | |
| products (id BIGSERIAL, metadata JSONB, tags TEXT[]) | products (id BIGINT, metadata JSON, tags JSON) | JSONB→JSON, TEXT[]→JSON | |
| events (id BIGSERIAL, payload JSONB, recorded_at TIMESTAMPTZ) | events (id BIGINT, payload JSON, recorded_at DATETIME) | JSONB→JSON, TIMESTAMPTZ→DATETIME | |
| sessions (id UUID, user_id UUID, expires_at TIMESTAMPTZ) | sessions (id CHAR(36), user_id CHAR(36), expires_at DATETIME) | UUID→CHAR(36), TIMESTAMPTZ→DATETIME | |
| audit_logs (id BIGSERIAL, row_data JSONB, changed_at TIMESTAMPTZ) | audit_logs (id BIGINT, row_data JSON, changed_at DATETIME) | JSONB→JSON — high-volume table, consider partitioning in MySQL |
rsync.ai vs. Fivetran, Airbyte, AWS DMS for PostgreSQL → MySQL
What you give up — and gain — choosing rsync.ai for Postgres to MySQL replication.