Skip to main content
PostgreSQL → MySQL

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.

TL;DR

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 it works

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. 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. 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. 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. 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. 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.

Featurersync.aiyouFivetranAirbyteAWS 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?

Near real time. After the initial snapshot, rsync.ai reads change events from the PostgreSQL WAL via logical replication and writes them to MySQL continuously. End-to-end lag depends on transaction volume and the network distance between Postgres, rsync.ai and MySQL.

How are PostgreSQL types mapped to MySQL types — especially UUID and JSONB?

rsync.ai applies a deterministic type mapping: UUID→CHAR(36), JSONB→JSON, JSON→JSON, TEXT[]→JSON, INTEGER[]→JSON, TIMESTAMPTZ→DATETIME (UTC, precision 6), TIMESTAMP→DATETIME, DATE→DATE, BOOLEAN→TINYINT(1), NUMERIC(p,s)→DECIMAL(p,s), BYTEA→LONGBLOB, and TEXT→LONGTEXT (or VARCHAR(255) for short columns). You can override any mapping in the approve step before the pipeline starts.

What happens with MySQL reserved keywords in PostgreSQL column names?

rsync.ai detects MySQL reserved keywords in the proposed DDL (e.g., `order`, `rank`, `key`, `desc`) and automatically backtick-quotes them in the CREATE TABLE and all subsequent DML. You'll see a warning in the approve step listing any renamed or quoted identifiers so there are no surprises.

Do tables need a primary key in PostgreSQL for CDC to work?

For UPDATE and DELETE events, PostgreSQL logical replication requires either a primary key or REPLICA IDENTITY FULL set on the table. Without one, Postgres cannot identify which row changed. rsync.ai warns you if it detects tables in the publication that lack a primary key or REPLICA IDENTITY FULL. INSERT-only tables work fine without a primary key.

What happens if rsync.ai is down for several hours — are changes lost?

No. The PostgreSQL replication slot retains all WAL segments until rsync.ai confirms it has consumed them. When rsync.ai restarts, it resumes from the last committed LSN. The MySQL destination is written idempotently (upsert on primary key for INSERTs and UPDATEs), so if rsync.ai replays events after a restart, no duplicate rows appear. Monitor WAL disk usage on Postgres if downtime is extended — set `max_slot_wal_keep_size` (Postgres 13+) to guard against disk exhaustion.

How does rsync.ai handle schema changes (ALTER TABLE) in PostgreSQL?

DDL events (ALTER TABLE ADD COLUMN, DROP COLUMN, etc.) are not part of the pgoutput logical replication stream. rsync.ai detects schema drift by comparing the replication message column list against the known schema. New columns and column type changes are applied to MySQL and recorded in the pipeline's history. A dropped column stays in MySQL, and the change is recorded. Only a dropped table waits for a person to decide what happens next.

Can rsync.ai mask PII columns before they reach MySQL?

Yes. In the pipeline configuration, mark any column as `masked` — rsync.ai replaces the value with a SHA-256 hash or NULL before writing to MySQL. Masking happens inside the rsync.ai pipeline process: the raw value is never written to MySQL. Common use cases: email, phone, SSN in users or orders tables.

Is rsync.ai self-hosted for PostgreSQL to MySQL replication?

rsync.ai Cloud is live today at app.rsync.ai — nothing to deploy. You can self-host the full stack today — one command (`curl -sSL https://raw.githubusercontent.com/rsync-ai/rsync.ai/main/install.sh | bash`) brings it up inside your own VPC, so your PostgreSQL replication credentials and MySQL password never leave your network. rsync.ai is source-available under the rsync.ai Source-Available License: self-hosting is free for your company's own internal use, while reselling it or hosting it for others as a service needs a commercial license.

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.

Start free