MySQL to Azure Database for MySQL Flexible Server Migration¶
Migrating MySQL Community or Enterprise Edition to Azure Database for MySQL Flexible Server: version compatibility, server parameter mapping, character set handling, storage configuration, IOPS tuning, and HA architecture.
Migration summary
Azure Database for MySQL Flexible Server runs the same MySQL Community Edition engine as your source database. For MySQL 5.7 and 8.0 workloads, migration is a same-engine move -- no schema conversion, no SQL syntax changes, no stored procedure rewriting. The primary work involves parameter mapping, networking configuration, and data movement. MySQL 5.6 and earlier must upgrade to 5.7 or 8.0 before migrating.
1. Version compatibility¶
1.1 Supported versions on Azure MySQL Flexible Server¶
| MySQL version | Azure MySQL Flexible Server support | End of life | Notes |
|---|---|---|---|
| MySQL 8.4 (LTS) | Supported | TBD (LTS track) | Long-term support version, recommended for new deployments |
| MySQL 8.0 | Supported | April 2026 | Most common production version; plan upgrade to 8.4 |
| MySQL 5.7 | End of support Oct 2025 | October 2025 | Migrate to 8.0 or 8.4 during migration to Azure |
| MySQL 5.6 | Not supported | February 2021 | Must upgrade to 5.7 or 8.0 first |
| MySQL 5.5 and earlier | Not supported | December 2018 | Must upgrade through 5.6 -> 5.7 -> 8.0 |
1.2 MariaDB version compatibility¶
MariaDB is not natively supported on Azure MySQL Flexible Server, but MariaDB 10.x workloads can migrate to Azure MySQL Flexible Server with caveats:
| MariaDB version | Migration path | Key considerations |
|---|---|---|
| MariaDB 10.2-10.6 | Migrate to Azure MySQL Flexible Server 8.0 | MariaDB-specific SQL (sequences, system versioning) must be converted |
| MariaDB 10.7-10.11 | Migrate to Azure MySQL Flexible Server 8.0/8.4 | Increasing divergence; test thoroughly |
| MariaDB 11.x | Evaluate case-by-case | Significant feature divergence; consider PostgreSQL as alternative target |
1.3 Pre-migration version upgrade path¶
If your source is MySQL 5.6 or earlier, follow this upgrade path before migrating to Azure:
Each version upgrade should be tested in a staging environment. Key upgrade considerations:
- 5.6 to 5.7:
sql_modedefaults change (STRICT_TRANS_TABLES, ONLY_FULL_GROUP_BY),PASSWORD()function removed,mysql_old_passwordplugin removed - 5.7 to 8.0:
utf8mb4becomes default charset,caching_sha2_passwordbecomes default auth plugin, query cache removed,GROUP BYimplicit sorting removed - 8.0 to 8.4: Minor behavioral changes; LTS version with extended support
2. Server parameter mapping¶
2.1 Critical parameters¶
Azure MySQL Flexible Server exposes most MySQL server parameters through the Azure portal, CLI, or API. Some parameters are not configurable because they are managed by the service.
| Parameter | Self-hosted default | Azure Flexible Server | Configurable | Notes |
|---|---|---|---|---|
| innodb_buffer_pool_size | 128 MB (default) / tuned by DBA | Auto-sized based on SKU (50-80% of RAM) | Yes | Set via server parameter |
| innodb_buffer_pool_instances | 8 (when buffer pool > 1 GB) | Auto-configured based on SKU | No | Managed by service |
| innodb_log_file_size | 48 MB (default) / tuned by DBA | Auto-sized based on SKU | No | Managed by service |
| innodb_flush_log_at_trx_commit | 1 (full durability) | 1 (default, recommended) | Yes | Set to 2 for performance (reduced durability) |
| innodb_flush_method | fsync (default) | O_DIRECT | No | Optimized by service |
| max_connections | 151 (default) | SKU-based (varies by tier) | Yes | Burstable: 50-800, GP: 100-5000, MO: 200-10000 |
| max_allowed_packet | 64 MB | 64 MB (default) | Yes | Up to 1 GB |
| wait_timeout | 28800 | 28800 | Yes | Reduce for connection-heavy workloads |
| interactive_timeout | 28800 | 28800 | Yes | Match wait_timeout |
| innodb_lock_wait_timeout | 50 | 50 | Yes | Increase for long-running transactions |
| sql_mode | Varies by version | MySQL 8.0 defaults | Yes | Match source sql_mode during migration |
| character_set_server | varies | utf8mb4 | Yes | Match source; plan migration to utf8mb4 |
| collation_server | varies | utf8mb4_0900_ai_ci (8.0) | Yes | Match source during migration |
| lower_case_table_names | 0 (Linux) / 1 (Windows) | 1 (default on Azure) | Yes (at creation only) | Must be set during server creation; cannot be changed later |
| log_bin_trust_function_creators | OFF | OFF | Yes | Set to ON if using functions with deterministic issues |
| local_infile | OFF | OFF | Yes | Enable if using LOAD DATA LOCAL INFILE |
| event_scheduler | OFF | OFF | Yes | Enable if using MySQL events |
| binlog_expire_logs_seconds | 2592000 (30 days) | Managed by service | No | Managed for replication |
| slow_query_log | OFF | OFF (enable recommended) | Yes | Enable for performance monitoring |
| long_query_time | 10 | 10 | Yes | Reduce to 1-2 seconds for production monitoring |
2.2 Parameters not available on Flexible Server¶
These parameters cannot be set because the service manages them:
| Parameter | Reason |
|---|---|
| basedir / datadir | Managed by service |
| bind-address | Networking managed by Azure |
| skip-networking | Always network-enabled |
| innodb_data_file_path | Managed storage |
| innodb_log_group_home_dir | Managed storage |
| pid-file | Managed by service |
| socket | Managed by service |
| tmpdir | Managed by service |
| secure-file-priv | Managed by service |
| plugin_dir | Managed by service (limited plugins) |
2.3 Exporting current parameters¶
Capture your source server's parameter configuration before migration:
-- Export all global variables
SELECT @@global.variable_name, @@global.variable_value
FROM performance_schema.global_variables
ORDER BY variable_name;
-- Or use SHOW VARIABLES
SHOW GLOBAL VARIABLES;
-- Save to file
mysql -u root -p -e "SHOW GLOBAL VARIABLES" > /tmp/mysql_variables.txt
-- Key parameters to capture and map
SHOW VARIABLES LIKE 'innodb_%';
SHOW VARIABLES LIKE 'max_%';
SHOW VARIABLES LIKE 'character%';
SHOW VARIABLES LIKE 'collation%';
SHOW VARIABLES LIKE 'sql_mode';
SHOW VARIABLES LIKE 'lower_case%';
SHOW VARIABLES LIKE 'time_zone';
3. Character set and collation handling¶
3.1 Character set migration¶
| Source charset | Target charset | Action required |
|---|---|---|
| utf8mb4 | utf8mb4 | No change (recommended) |
| utf8 (utf8mb3) | utf8mb4 (recommended) or utf8mb3 | Convert to utf8mb4 for full Unicode support |
| latin1 | utf8mb4 (recommended) or latin1 | Convert to utf8mb4; watch for data truncation |
| ascii | utf8mb4 or ascii | Convert to utf8mb4 (superset) |
| binary | binary | No change |
3.2 Collation mapping¶
| Source collation | Target collation | Notes |
|---|---|---|
| utf8mb4_unicode_ci | utf8mb4_unicode_ci or utf8mb4_0900_ai_ci | 0900 collation is faster on MySQL 8.0 |
| utf8mb4_general_ci | utf8mb4_general_ci or utf8mb4_0900_ai_ci | general_ci is faster but less correct |
| utf8_general_ci | utf8mb4_general_ci | Convert charset simultaneously |
| latin1_swedish_ci | utf8mb4_0900_ai_ci (recommended) | Full Unicode support |
| binary | binary | No change |
3.3 Converting character sets¶
-- Check current database character set
SELECT schema_name, default_character_set_name, default_collation_name
FROM information_schema.schemata;
-- Check table character sets
SELECT table_name, table_collation
FROM information_schema.tables
WHERE table_schema = 'your_database';
-- Check column character sets
SELECT table_name, column_name, character_set_name, collation_name
FROM information_schema.columns
WHERE table_schema = 'your_database'
AND character_set_name IS NOT NULL;
-- Convert database
ALTER DATABASE your_database CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- Convert table
ALTER TABLE your_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- Convert specific column
ALTER TABLE your_table MODIFY column_name VARCHAR(255)
CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
4. Storage configuration¶
4.1 Storage tier selection¶
| Storage tier | IOPS (baseline) | Max IOPS | Max storage | Best for |
|---|---|---|---|---|
| Premium SSD | 3 IOPS/GB | Up to 20,000 (storage-scaled) | 16 TB | Standard production workloads |
| Premium SSD + Pre-provisioned IOPS | 3 IOPS/GB + additional | Up to 80,000 | 16 TB | I/O-intensive workloads |
4.2 Sizing storage from source¶
-- Get total database size
SELECT
table_schema AS 'Database',
ROUND(SUM(data_length + index_length) / 1024 / 1024 / 1024, 2) AS 'Size (GB)',
ROUND(SUM(data_length) / 1024 / 1024 / 1024, 2) AS 'Data (GB)',
ROUND(SUM(index_length) / 1024 / 1024 / 1024, 2) AS 'Index (GB)'
FROM information_schema.tables
GROUP BY table_schema
ORDER BY SUM(data_length + index_length) DESC;
-- Get IOPS baseline (requires performance_schema or OS tools)
-- On Linux, use iostat:
-- iostat -x 1 60 | grep sda
-- Capture: r/s (reads/sec) + w/s (writes/sec) = total IOPS
Sizing guideline: Provision storage at 1.5x current data size to account for growth, temporary tables, and InnoDB overhead. For IOPS, capture peak IOPS from your source server and provision accordingly.
4.3 Storage auto-grow¶
Enable storage auto-grow to prevent out-of-space failures:
# Azure CLI
az mysql flexible-server update \
--resource-group myResourceGroup \
--name myMySQLServer \
--storage-auto-grow Enabled
Storage auto-grow increases storage in increments when free space falls below a threshold. Storage can only grow -- it cannot shrink. Plan initial sizing carefully to avoid paying for over-provisioned storage.
5. IOPS configuration¶
5.1 Understanding IOPS on Flexible Server¶
IOPS on Azure MySQL Flexible Server can be scaled in two ways:
- Storage-scaled IOPS: 3 IOPS per GB of provisioned storage. A 1 TB server gets 3,000 IOPS baseline.
- Pre-provisioned IOPS: Additional IOPS purchased independently of storage. Allows up to 80,000 IOPS regardless of storage size.
5.2 IOPS sizing from source workload¶
-- Check InnoDB I/O statistics
SHOW GLOBAL STATUS LIKE 'Innodb_data_reads';
SHOW GLOBAL STATUS LIKE 'Innodb_data_writes';
SHOW GLOBAL STATUS LIKE 'Innodb_data_fsyncs';
SHOW GLOBAL STATUS LIKE 'Innodb_os_log_written';
-- Query performance_schema for I/O wait events
SELECT event_name, count_star, sum_timer_wait/1000000000 AS total_wait_ms
FROM performance_schema.events_waits_summary_global_by_event_name
WHERE event_name LIKE 'wait/io/file/innodb/%'
ORDER BY sum_timer_wait DESC;
6. High availability architecture¶
6.1 HA options on Flexible Server¶
| HA mode | Architecture | Failover time | SLA | Cost impact |
|---|---|---|---|---|
| No HA | Single server | Manual recovery | 99.9% | 1x compute |
| Same-zone HA | Primary + standby in same AZ | 60-120 seconds | 99.99% | 2x compute |
| Zone-redundant HA | Primary + standby in different AZ | 60-120 seconds | 99.99% | 2x compute |
6.2 Mapping source HA to Azure HA¶
| Source HA pattern | Azure equivalent | Notes |
|---|---|---|
| MySQL async replication (manual failover) | Zone-redundant HA (automatic failover) | Significant improvement |
| MySQL semi-sync replication | Zone-redundant HA | Similar durability, automated failover |
| MySQL Group Replication (single-primary) | Zone-redundant HA | Simplified, same or better availability |
| MySQL InnoDB Cluster | Zone-redundant HA | Service-managed, no MySQL Shell/Router needed |
| MariaDB Galera Cluster (multi-primary) | Zone-redundant HA (single-primary) | Multi-primary not supported; redesign for single-primary if needed |
| ProxySQL + replication (read/write split) | Primary + read replicas (up to 10) | Application manages routing |
| MHA (Master High Availability) | Zone-redundant HA | Service-managed, MHA not needed |
| Orchestrator (automated failover) | Zone-redundant HA | Service-managed, Orchestrator not needed |
| Keepalived + VIP | Built-in DNS failover | No VIP management needed |
6.3 HA configuration¶
# Create Flexible Server with zone-redundant HA
az mysql flexible-server create \
--resource-group myResourceGroup \
--name myMySQLServer \
--location eastus \
--sku-name Standard_D4ds_v4 \
--tier GeneralPurpose \
--storage-size 256 \
--high-availability ZoneRedundant \
--zone 1 \
--standby-zone 2 \
--admin-user myadmin \
--admin-password 'ComplexPassword123!'
# Add read replicas for read scale-out
az mysql flexible-server replica create \
--resource-group myResourceGroup \
--name myMySQLReplica \
--source-server myMySQLServer \
--location eastus
7. Networking configuration¶
7.1 Connectivity options¶
| Option | Description | Best for |
|---|---|---|
| Public access with firewall | Public endpoint with IP-based firewall rules | Dev/test, simple deployments |
| Private access (VNet integration) | Server deployed into a VNet subnet | Production, compliance-sensitive workloads |
| Private Link | Private endpoint in your VNet | Hybrid connectivity, multi-VNet architectures |
7.2 VNet integration setup¶
# Create Flexible Server with VNet integration
az mysql flexible-server create \
--resource-group myResourceGroup \
--name myMySQLServer \
--location eastus \
--sku-name Standard_D8ds_v4 \
--tier GeneralPurpose \
--storage-size 512 \
--vnet myVNet \
--subnet mySubnet \
--private-dns-zone myPrivateDnsZone
7.3 DNS configuration¶
Azure MySQL Flexible Server with VNet integration uses Azure Private DNS zones. Ensure your application DNS resolution points to the private DNS zone:
- Private DNS zone format:
<server-name>.private.mysql.database.azure.com - Public endpoint format:
<server-name>.mysql.database.azure.com
8. Pre-migration checklist¶
- Verify source MySQL version is 5.7 or 8.0 (upgrade if earlier)
- Confirm all tables use InnoDB (convert MyISAM, Aria, MEMORY tables)
- Capture current server parameters (
SHOW GLOBAL VARIABLES) - Document character sets and collations for all databases, tables, columns
- Inventory stored procedures, triggers, events, and views
- Identify usage of SUPER privilege and refactor
- Test with
lower_case_table_names=1if source uses case-sensitive table names - Review application connection strings and SSL/TLS configuration
- Capture performance baselines (slow query log, IOPS, connection counts)
- Size target compute and storage based on source metrics
- Choose HA mode (no HA, same-zone, zone-redundant)
- Plan networking (public, VNet integration, Private Link)
- Configure Entra ID authentication if replacing MySQL passwords
- Schedule maintenance window for production cutover
Next: Schema Migration | Data Migration | Tutorial: DMS Online Migration
Maintainers: csa-inabox core team Last updated: 2026-04-30