Alternative Solutions for MySQL to PostgreSQL Migration: Updated to show Alternative Approach to Migrate MySQL to Postgres
What Azure DMS Actually Supports:
- MySQL → Azure Database for MySQL
- PostgreSQL → Azure Database for PostgreSQL
- SQL Server → Azure SQL Database/MI
- MongoDB → Azure Cosmos DB
What it DOESN’T Support:
- MySQL → PostgreSQL ❌
- Oracle → PostgreSQL ❌
- Any cross-engine migrations ❌
Since Azure DMS won’t work for your use case, here are the best alternatives for zero-downtime migration:
1. AWS Database Migration Service (DMS) For a comprehensive zero-downtime migration using AWS DMS, see our detailed guide.
AWS DMS actually DOES support MySQL to PostgreSQL migrations with continuous replication:
# AWS DMS supports this migration path
Source: MySQL (on Azure) → Target: PostgreSQL (on Azure)Use AWS DMS even when both databases are on Azure - it’s just a migration tool.
pgloader - Excellent for MySQL to PostgreSQL:
# One-time migration
pgloader mysql://user:pass@mysql-host/db postgresql://user:pass@pg-host/db
# With transformation rules
pgloader --verbose --debug mysql://source postgresql://targetDebezium + Kafka for real-time replication:
# Debezium MySQL Source Connector
{
"connector.class": "io.debezium.connector.mysql.MySqlConnector",
"database.hostname": "your-mysql-host",
"transforms": "unwrap",
"transforms.unwrap.type": "io.debezium.transforms.ExtractNewRecordState"
}Phase 1: Schema Migration
# Export MySQL schema and convert to PostgreSQL
mysqldump --no-data --routines --triggers source_db > mysql_schema.sql
# Use conversion tools or manual conversionPhase 2: Initial Data Load
# Use pgloader or custom ETL
pgloader --with "prefetch rows = 10000" \
--with "batch size = 25MB" \
mysql://source postgresql://targetPhase 3: Change Data Capture
- Set up binlog reading from MySQL
- Stream changes to PostgreSQL via custom application
- Use tools like Maxwell’s daemon or Debezium
During migration period:
def write_data(data):
# Write to both databases during transition
mysql_connection.execute(mysql_query, data)
postgresql_connection.execute(pg_query, converted_data)
# Validate consistency
if validate_enabled:
validate_data_consistency(data)Option 1: AWS DMS (Easiest)
- Set up AWS DMS instance
- Configure MySQL (Azure) as source
- Configure PostgreSQL (Azure) as target
- Run continuous replication
- Perform cutover when synchronized
Option 2: Debezium + Custom Pipeline
- Deploy Kafka cluster
- Set up Debezium MySQL connector
- Create transformation logic for MySQL→PostgreSQL data types
- Stream to PostgreSQL via Kafka Connect PostgreSQL sink
- Monitor lag and perform cutover
Would you like me to provide detailed implementation steps for either of these approaches? AWS DMS would be the quickest solution since it handles the cross-engine conversion automatically.
On Azure without downtime requires a carefully planned approach using logical replication and synchronized cutover strategies:
Azure DMS is the recommended tool for this migration as it supports online (minimal downtime) migrations:
- Setup Azure DMS
- Create an Azure Database Migration Service instance
- Configure network connectivity between source MySQL and target PostgreSQL
- Ensure proper firewall rules and VNet peering if needed
- Configure Continuous Sync
- Enable binary logging on MySQL source
- Create migration project in DMS with “Online migration” selected
- DMS will perform initial data load and then continuously sync changes
If Azure DMS doesn’t meet your needs, use a custom logical replication approach:
Phase 1: Initial Setup
-- On MySQL source
SET GLOBAL binlog_format = 'ROW';
SET GLOBAL binlog_row_image = 'FULL';
-- Create replication user
CREATE USER 'repl_user'@'%' IDENTIFIED BY 'secure_password';
GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%';Phase 2: Schema Migration
- Use tools like
pgloaderor custom scripts to convert schema - Handle data type differences (MySQL → PostgreSQL)
- Migrate indexes, constraints, and triggers separately
Phase 3: Data Synchronization Tools
- AWS DMS (works with Azure): Can replicate from MySQL to PostgreSQL
- Debezium + Kafka: Stream changes from MySQL binlog to PostgreSQL
- Custom ETL pipeline: Using tools like Apache Airflow
# Schema assessment and conversion
mysqldump --no-data --routines --triggers source_db > schema.sql
# Convert MySQL schema to PostgreSQL format- Create Azure Database for PostgreSQL
- Configure performance tier matching source workload
- Setup monitoring and backup policies
# Using pgloader for initial migration
pgloader mysql://user:pass@mysql-host/db postgresql://user:pass@pg-host/dbUse Debezium for change data capture:
# Debezium connector configuration
{
"name": "mysql-postgres-connector",
"config": {
"connector.class": "io.debezium.connector.mysql.MySqlConnector",
"database.hostname": "mysql-host",
"database.port": "3306",
"database.user": "repl_user",
"database.password": "password",
"database.server.id": "12345",
"database.server.name": "mysql-server",
"database.include.list": "your_database",
"transforms": "route",
"transforms.route.type": "org.apache.kafka.connect.transforms.RegexRouter",
"transforms.route.regex": "([^.]+)\\.([^.]+)\\.([^.]+)",
"transforms.route.replacement": "$3"
}
}- Modify application to write to both MySQL and PostgreSQL
- Read from MySQL initially
- Validate data consistency between databases
# Application code example
if feature_flag_enabled('use_postgresql'):
result = postgresql_query(sql)
else:
result = mysql_query(sql)- Use ORM or database abstraction layer
- Switch database connections via configuration
- Handle SQL dialect differences
-- Compare row counts
SELECT COUNT(*) FROM mysql_table;
SELECT COUNT(*) FROM postgresql_table;
-- Checksum validation
SELECT MD5(CONCAT_WS('|', col1, col2, col3)) FROM mysql_table ORDER BY id;
SELECT MD5(string_agg(col1||'|'||col2||'|'||col3, '' ORDER BY id)) FROM postgresql_table;- Run load tests against PostgreSQL
- Compare query performance
- Validate connection pooling and caching
# 1. Stop application writes
# 2. Wait for replication lag to reach zero
# 3. Perform final data validation
# 4. Switch application configuration
# 5. Start application with PostgreSQL- Keep MySQL running for 24-48 hours
- Monitor application metrics
- Have immediate rollback procedure ready
- Use Azure Private Link for secure connectivity
- Configure VNet integration for DMS
- Setup NSG rules for database access
# Azure CLI monitoring setup
az monitor metrics alert create \
--name "PostgreSQL-CPU-Alert" \
--resource-group myResourceGroup \
--scopes "/subscriptions/.../resourceGroups/.../providers/Microsoft.DBforPostgreSQL/servers/myserver" \
--condition "avg Percentage CPU > 80"- Configure automated backups for PostgreSQL
- Test point-in-time recovery
- Document backup retention policies
-- MySQL to PostgreSQL mappings
TINYINT(1) → BOOLEAN
DATETIME → TIMESTAMP
ENUM → VARCHAR with CHECK constraint
AUTO_INCREMENT → SERIAL or IDENTITY- Replace MySQL-specific functions
- Handle LIMIT/OFFSET differences
- Update stored procedures and triggers
- Ensure UTF-8 encoding consistency
- Handle collation differences
- Test special characters thoroughly
This approach minimizes downtime to minutes during the final cutover while ensuring data consistency and providing rollback capabilities. The key is thorough testing and having multiple validation checkpoints throughout the process.