Home / Databases / MySQL

DatabasesRunbookIntermediate

Transformation: MySQL from VMs or on-premises to Azure Database for MySQL Flexible Server

Move self-managed MySQL to Azure Database for MySQL Flexible Server. Check compatibility, create a right-sized server, do the initial load with mydumper/myloader or Azure DMS, keep it in sync with data-in replication, and cut over in minutes.

Deepak Bhardwaj3 min read

Applies toMySQL 5.7 and 8.0/8.4 sources; Azure Database for MySQL Flexible Server (8.0, 8.4; check current versions); Azure Database Migration Service

1. Compatibility check

Check Why
Storage engines (SELECT engine, count(*) FROM information_schema.tables GROUP BY engine;) InnoDB only; convert MyISAM tables first
SUPER privilege use, DEFINER clauses, plugins No SUPER on Flexible Server; definers must exist; limited plugins
lower_case_table_names Set at server creation for 8.0+; must match the app
Tables without primary keys Replication performance; Flexible Server can enforce sql_generate_invisible_primary_key
Version 5.7 sources should move to 8.0/8.4. Do the version jump deliberately (see the 8.0 → 8.4 upgrade post)

2. Create the target

az mysql flexible-server create -g rg-db -n mysqlflex-shop --version 8.0.21 \
  --tier GeneralPurpose --sku-name Standard_D4ds_v4 --storage-size 512 --auto-scale-iops Enabled \
  --high-availability ZoneRedundant --vnet vnet-db --subnet snet-mysql

Check az mysql flexible-server list-skus and supported versions for your region. Copy important server parameters (max_connections, innodb_buffer_pool_size is managed, time_zone, sql_mode).

3. Choose the method

Method Downtime Use when
Azure DMS (online MySQL migration) Minutes Supported source/target combination; you want a managed workflow
mydumper/myloader + data-in replication Minutes Large databases, more control
mysqldump Hours Small databases, long window

4. mydumper + data-in replication path

Source prerequisites: log_bin on, binlog_format=ROW, gtid_mode=ON recommended, a replication user, network path from Azure to the source on 3306 (VPN/ExpressRoute).

Initial load with a consistent snapshot:

mydumper -h src-mysql -u dumper -p '***' -B shop -t 8 --trx-consistency-only -o /mnt/dump/shop
myloader -h mysqlflex-shop.mysql.database.azure.com -u azadmin -p '***' -B shop -t 8 -d /mnt/dump/shop

The dump's metadata file records the binlog position / GTID set at the snapshot.

Start replication on Flexible Server (GTID-based):

CALL mysql.az_replication_change_master_with_gtid('src-mysql.example.com', 'repl', '<password>', 3306, '');
CALL mysql.az_replication_start;
SHOW REPLICA STATUS\G

With GTIDs, first set gtid_purged on the target to the GTID set in the dump metadata. Flexible Server provides a stored procedure for this because you have no SUPER. Position-based alternative: mysql.az_replication_change_master with file and position from the metadata. Check the current procedure names in the Azure docs for your version.

5. Validate

  • Row counts and checksums on key tables (pt-table-checksum works across replication).
  • Users and grants recreated without SUPER; DEFINER users exist.
  • Events, triggers, routines present.
  • App tests with TLS (require_secure_transport is ON by default).

6. Cut-over

  1. Stop writes on the source (read-only: SET GLOBAL super_read_only = ON;).
  2. Wait for Seconds_Behind_Source = 0 and matching GTID sets.
  3. CALL mysql.az_replication_stop; then CALL mysql.az_replication_remove_master;.
  4. Switch connection strings; check AUTO_INCREMENT values continue correctly.
  5. Keep the source read-only for the rollback window.

7. After go-live

  • Alerts: CPU, storage %, IOPS, active connections, replication lag on read replicas.
  • Backups: retention and geo-redundancy settings; test a point-in-time restore.
  • Slow query log to Log Analytics (server parameters slow_query_log, log_output).

Warning

lower_case_table_names can't be changed after the server is created on MySQL 8.0+. Match the source (Windows sources often use 1 or 2) or fix table name casing in the app first.

Checklist

  • InnoDB only; SUPER/definers/plugins reviewed
  • Server created with correct version and lower_case_table_names
  • Initial load + data-in replication rehearsed
  • Validation and app TLS tested
  • Cut-over and rollback window agreed