Overview
| Property | Value |
|---|---|
| Engine ID | mysql |
| Wire Protocol | MySQL wire protocol (COM_* commands) |
| Classifier | AST-based (vitess/sqlparser) with regex fallback |
| Shadow | Docker mysql:<version> (version-matched) |
| Extended Protocol | COM_STMT_PREPARE/EXECUTE/CLOSE |
| Field | Description | Default |
|---|---|---|
host | Database host | — |
port | Database port | 3306 |
user | Username | — |
password | Password | — |
database | Database name | — |
ssl_mode | SSL mode | verify-full |
Differences from PostgreSQL
- No RETURNING clause — MySQL does not support
RETURNINGon INSERT/UPDATE/DELETE. PK extraction uses a 3-tier strategy: (1)LAST_INSERT_IDfrom OK packet for auto-increment tables, (2) Vitess AST parsing of INSERT VALUES clause for literal PKs, (3) fallback to aggregate insert count tracking. INSERT ... ON DUPLICATE KEY UPDATE— MySQL’s upsert syntax (equivalent to PostgreSQL’sON CONFLICT). Classified asHasOnConflictand routed through the hydration path.REPLACE INTO— MySQL-specific delete-then-insert semantics. Handled with upsert-like hydration: extracts PKs, hydrates matching prod rows, executes REPLACE, tombstones replaced prod-only rows.CHANGE COLUMN— MySQL’s combined rename + type change DDL. Tracked correctly in the schema registry.- Auto-increment offsets — Uses
ALTER TABLE ... AUTO_INCREMENT = Ninstead of PostgreSQL’ssetval()for sequence offsets. - No
ctidequivalent — PK-less tables use full-row deduplication. A warning is emitted during init for tables without primary keys. - No cursor support — MySQL cursors only work inside stored procedures, not as standalone SQL statements.
- No LISTEN/UNLISTEN — MySQL has no equivalent to PostgreSQL’s pub/sub system.
- Transaction isolation — Sends
START TRANSACTION WITH CONSISTENT SNAPSHOT, READ ONLYto prod for snapshot consistency.
Known Limitations
only_full_group_bymode conflicts with aggregate re-aggregation. Workaround:SET sql_mode = ''.- Multi-column ORDER BY not re-applied after merge (single-column sort only).
- Unsupported operations: CALL, EXPLAIN ANALYZE.
- Functions aren’t supported yet because it’s really hard to determine if the function is non-mutating or not.
- CTE updates/deletes/upserts might produce incorrect subsequent merged read results.
- Performance: Rare, but some extremely complex JOINs over large tables might be slow either because (a) the prod data needed is too large or (b) the query is too complex and the safety mechanism decides to materialize the result into a temporary table locally. If this happens, try passing in
--max-rowsduringmori start, which will cap the number of rows pulled from prod.

