Skip to content

PATTERN

Cross-engine database migration audit

Cross-engine database migration audit is a pre-migration pattern: before moving a schema between two SQL engines (e.g. PostgreSQL → MySQL), enumerate the differences along three orthogonal axes and confirm every source construct maps to a supported target construct.

The axes — from Adnan Kukic's PlanetScale audit () — are:

  1. Column-type axis — does every source column have a target equivalent? Does the equivalent behave the same way at the representation level, not just the declaration level?
  2. DDL/DML dialect axis — do CREATE, DROP, TRUNCATE, INSERT, ON CONFLICT / ON DUPLICATE KEY, stored procedures, triggers, views, and partitioning translate cleanly?
  3. Operational-semantics axis — identifier case sensitivity, transaction safety of DDL statements, extension ecosystems, sequence / auto-increment semantics.

Worked example: Postgres → MySQL audit

The canonical wiki instance is the 2023 PlanetScale post. Three sample tables surface three column-type classes:

Five operational-dialect gaps are called out:

Why this pattern is distinct from a same-engine upgrade

The PlanetScale audit enumerates within-engine breaking changes across a major-version bump (MySQL 5.7 → 8.0). The cross-engine audit applies the same discipline across engines, and picks up a further class of surprises — the representation-layer differences (MySQL WKB for POINT) that a version-bump audit would never surface because the representation doesn't change across MySQL versions.

What the pattern does not cover

A cross-engine migration audit is a schema + dialect readiness check. It does not address:

  • Data movement — how to copy rows between engines. For the zero-downtime data-movement playbook see

and patterns/snapshot-plus-catchup-replication. - Application cutover — how to route writes between old and new engines during overlap. See patterns/dual-write-migration, patterns/expand-migrate-contract. - Performance regression — query planner differences can change workload shape. EXPLAIN a representative workload on the target before cutover.

Exit criteria

Audit is complete when:

  • Every source column type has a declared target equivalent, including representation (not just declaration).
  • Every DDL / DML statement in the application's query log has a confirmed target-engine form, or a planned application-side rewrite.
  • Every stored procedure, trigger, and extension is either ported or explicitly dropped from the migration scope.
  • Identifier collisions under the target engine's case rules have been resolved.
  • EXPLAIN output on the target engine for top-N queries has been spot-checked against Postgres's expectations.

See also

Last updated · 542 distilled / 1,571 read