Skip to main content
MySQL → PostgreSQL

Sync MySQL to PostgreSQL
with real-time binlog CDC.

Replicate MySQL to PostgreSQL using binlog row-format CDC — sub-second lag, automatic type mapping, zero downtime. Migrate, replicate for analytics, or consolidate multiple MySQL databases into one Postgres.

TL;DR

rsync.ai connects to MySQL as a replica, reads binlog events in ROW format (GTID or file+position), snapshots your tables, then streams all subsequent changes to PostgreSQL in real time. MySQL types are mapped to Postgres equivalents automatically — TINYINT(1)→BOOLEAN, INT UNSIGNED→BIGINT, ENUM→TEXT, JSON→JSONB, DATETIME→TIMESTAMPTZ. Schema changes (ALTER TABLE) surface as review prompts. Works with MySQL 5.7+, RDS, Aurora, Cloud SQL, and PlanetScale.

  • Sub-second replication lag via binlog ROW-format CDC
  • GTID and file+position replication both supported
  • Auto type mapping — TINYINT(1)→BOOLEAN, UNSIGNED→BIGINT, ENUM→TEXT
  • DDL changes (ALTER TABLE) detected and propagated safely
How it works

How to replicate MySQL to PostgreSQL — 5 steps

From binlog setup to CDC streaming — typically under 10 minutes.

  1. 1

    Enable MySQL binlog

    Set `binlog_format=ROW` and `log_bin=ON` in your MySQL config (my.cnf / my.ini). Create a dedicated replication user: `CREATE USER 'rsync_cdc'@'%' IDENTIFIED BY '…'; GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'rsync_cdc'@'%';`. On Amazon RDS or Aurora, enable automated backups — that activates binlog automatically. Set the `binlog_format` parameter to ROW in your parameter group.

    binlog_format=ROW · log_bin=ON · REPLICATION SLAVE + REPLICATION CLIENT
  2. 2

    Connect MySQL source

    Provide your MySQL host, port (default 3306), replication username, password, and database name. rsync.ai connects as a replica, reads the current binlog position (or GTID set), and begins the initial snapshot of all selected tables. SSL/TLS and SSH tunnels are supported for databases inside a private VPC.

    mysql://rsync_cdc:pass@host:3306/mydb
  3. 3

    Connect PostgreSQL destination

    Provide your PostgreSQL host, port (default 5432), user, password, and target database. The user needs CREATE TABLE and INSERT/UPDATE/DELETE privileges on the target schema. rsync.ai will create the schema and tables for you if they don't already exist.

    postgres://user:pass@host:5432/analytics
  4. 4

    Describe the sync in plain English

    Tell rsync.ai what you want: 'Replicate all tables from MySQL mydb to PostgreSQL in real time.' The AI pipeline planner reads your MySQL schema, maps each table and column to Postgres equivalents, and proposes DDL for you to review. You can refine with follow-up instructions — 'exclude the sessions table' or 'hash the users.email column'.

    No SQL · No YAML · No DAGs
  5. 5

    Select tables, approve DDL, CDC starts

    rsync.ai shows each MySQL table with its proposed Postgres DDL and type mappings. Tick the tables you want, review any mapping decisions (UNSIGNED INT → BIGINT, TINYINT(1) → BOOLEAN, ENUM → TEXT with a CHECK constraint), then approve. rsync.ai takes a consistent snapshot, applies it to Postgres, then switches to streaming binlog events — sub-second lag at steady state.

    Snapshot → streaming CDC, zero-downtime

MySQL → PostgreSQL type mapping

rsync.ai proposes these mappings automatically. You review and approve every mapping before any data moves.

MySQL columnPostgreSQL columnNotes
users (INT UNSIGNED id, VARCHAR email, TINYINT(1) active)users (BIGINT id, TEXT email, BOOLEAN active)INT UNSIGNED → BIGINT prevents overflow. TINYINT(1) → BOOLEAN maps 0/1 to false/true.
orders (INT id, DECIMAL(10,2) total, DATETIME created_at)orders (INT id, NUMERIC(10,2) total, TIMESTAMPTZ created_at)DECIMAL → NUMERIC (exact semantics preserved). DATETIME → TIMESTAMPTZ with UTC normalisation.
products (INT id, TEXT description, JSON metadata)products (INT id, TEXT description, JSONB metadata)MySQL JSON → Postgres JSONB. JSONB allows indexing and operator queries.
sessions (VARCHAR(36) id, ENUM('active','expired') status)sessions (VARCHAR(36) id, TEXT status)MySQL ENUM → TEXT with a CHECK constraint enforcing the same allowed values.
transactions (BIGINT id, DECIMAL(18,8) amount, DATETIME ts)transactions (BIGINT id, NUMERIC(18,8) amount, TIMESTAMPTZ ts)High-precision DECIMAL preserved as NUMERIC. Sub-second timestamps retained via TIMESTAMPTZ.
audit_log (BIGINT id, VARCHAR(255) action, TEXT payload, DATETIME logged_at)audit_log (BIGINT id, VARCHAR(255) action, TEXT payload, TIMESTAMPTZ logged_at)High-volume append-only table. rsync.ai applies INSERTs only — no UPDATEs or DELETEs expected.

rsync.ai vs. Fivetran, Airbyte, AWS DMS for MySQL → PostgreSQL

Honest trade-offs for real-time MySQL to Postgres replication.

Feature
rsync.aiyou
Fivetran
Airbyte
AWS DMS
Real-time MySQL binlog CDC
Plain-English pipeline setup
Auto MySQL → Postgres type mapping
DDL change propagation (ALTER TABLE)
Self-hosted (data stays in your VPC)
Source-available connector code
No per-row / per-MAR pricing
Column-level PII masking

MySQL to PostgreSQL — frequently asked

How much latency does MySQL → PostgreSQL CDC introduce?

At steady state, rsync.ai typically delivers MySQL changes to PostgreSQL within 100–500 ms of the transaction committing, depending on network latency between your MySQL host and the rsync.ai process. The initial snapshot takes longer — proportional to the table size — but CDC streaming starts in parallel as soon as the snapshot is complete, so the pipeline is never fully idle.

How does rsync.ai handle MySQL TINYINT(1) and UNSIGNED integers in PostgreSQL?

MySQL's TINYINT(1) is conventionally used as a boolean (0/1). rsync.ai maps it to PostgreSQL BOOLEAN automatically. MySQL's unsigned integer types (TINYINT UNSIGNED, SMALLINT UNSIGNED, INT UNSIGNED, BIGINT UNSIGNED) are promoted to the next larger signed Postgres type — SMALLINT, INT, BIGINT, and NUMERIC respectively — to prevent overflow. You can override any mapping in the DDL review step.

How are MySQL ENUMs handled in PostgreSQL?

MySQL ENUM columns are mapped to TEXT in PostgreSQL with a CHECK constraint that enforces the same set of allowed values (e.g. `CHECK (status IN ('active','inactive','pending'))`). Postgres native ENUM types are intentionally avoided because they require an ALTER TYPE to add values, which can block production traffic. The TEXT + CHECK approach is schema-compatible with MySQL and alters safely with ALTER TABLE … ADD CHECK.

Does rsync.ai require a primary key on every MySQL table?

A primary key (or unique not-null key) is strongly recommended — without one, rsync.ai cannot perform row-level upserts and must apply CDC events in order, which reduces throughput. For tables without a primary key rsync.ai falls back to INSERT-only mode (useful for append-only audit logs). You'll see a warning during the DDL review step for any table without a usable key.

What happens if MySQL restarts while rsync.ai is running?

rsync.ai persists the last acknowledged binlog position (or GTID set) to its control plane database after each batch of events is committed to PostgreSQL. When MySQL restarts, rsync.ai reconnects and resumes from that saved position — no events are lost and no rows are duplicated. If MySQL has rotated past the saved position (binlog purged), rsync.ai detects the gap and re-snapshots the affected tables automatically.

Can rsync.ai handle MySQL schema changes (ALTER TABLE) automatically?

rsync.ai detects DDL events in the binlog (ALTER TABLE, CREATE TABLE, DROP TABLE) and applies equivalent changes to PostgreSQL where safe — adding a nullable column, for example. Destructive or ambiguous DDL (DROP COLUMN, changing a column type) surfaces as a review prompt in the UI rather than being applied automatically. This prevents silent data loss from a schema change in a development database accidentally propagating to production.

Can I redact or mask PII columns before they reach PostgreSQL?

Yes. In the pipeline configuration you can mark any column as: Null (value replaced with NULL), Hashed (SHA-256 of the original value — consistent for joins, unreadable as plaintext), or Truncated (for strings, only the first N characters). Masking is applied in rsync.ai's processing layer — the raw value is never written to PostgreSQL or any log.

How does rsync.ai compare to AWS DMS for MySQL → PostgreSQL?

AWS DMS is solid but opaque — you configure it through AWS console forms with no plain-English interface, type mapping bugs require opening a support ticket, and it runs only in AWS. rsync.ai is self-hosted, source-available (you can read and patch the connector code), and uses an AI planner to handle type mapping decisions automatically. For teams migrating off MySQL to Postgres, rsync.ai's DDL review step shows you every mapping decision before a single row moves.