Sync PostgreSQL to MySQL
with real-time CDC.
Stream every INSERT, UPDATE, and DELETE from PostgreSQL to MySQL 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 — no polling
- Automatic type mapping: UUID, JSONB, TIMESTAMPTZ, arrays
- Initial snapshot + live streaming — consistent from day one
- Self-host in your own VPC — source-available under the rsync.ai Source-Available License
How to sync PostgreSQL to MySQL — 5 steps
From enabling logical replication to rows streaming into MySQL. Once the data lands, query it in the SQL Explorer or with Ask rsync.ai, shape it with Models, and publish Charts and Dashboards.
- 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) streams to MySQL continuously after the snapshot.
Initial snapshot → live CDC stream
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.
| Feature | rsync.aiyou | Fivetran | Airbyte | AWS DMS |
|---|---|---|---|---|
| Real-time CDC (logical replication) | ||||
| Plain-English pipeline setup | ||||
| Automatic UUID / JSONB type mapping | ||||
| Self-host in your own VPC | ||||
| Source-available connector code | ||||
| No per-row / per-MAR pricing | ||||
| Resume after downtime (no data loss) | ||||
| PII column masking built-in |
PostgreSQL to MySQL — frequently asked
What is the CDC latency from PostgreSQL to MySQL?
How are PostgreSQL types mapped to MySQL types — especially UUID and JSONB?
What happens with MySQL reserved keywords in PostgreSQL column names?
Do tables need a primary key in PostgreSQL for CDC to work?
What happens if rsync.ai is down for several hours — are changes lost?
How does rsync.ai handle schema changes (ALTER TABLE) in PostgreSQL?
Can rsync.ai mask PII columns before they reach MySQL?
Is rsync.ai self-hosted for PostgreSQL to MySQL replication?
Run your first PostgreSQL to MySQL pipeline free
The first 10 GB of data moved is free. Describe the sync in plain English and review the plan before anything runs.