Back to Blog
3 min read

High Availability Architecture for MySQL on Azure

High availability is critical for production MySQL databases. Azure Database for MySQL Flexible Server offers built-in high availability options to ensure your database remains accessible even during failures.

HA Architecture Options

Zone-Redundant High Availability

# Create a zone-redundant HA server
az mysql flexible-server create \
    --resource-group myResourceGroup \
    --name myhaserver \
    --location eastus \
    --admin-user myadmin \
    --admin-password 'SecurePassword123!' \
    --sku-name Standard_D4ds_v4 \
    --tier GeneralPurpose \
    --high-availability ZoneRedundant \
    --zone 1 \
    --standby-zone 2

Same-Zone High Availability

# Create a same-zone HA server (lower cost)
az mysql flexible-server create \
    --resource-group myResourceGroup \
    --name myhaserver-samezone \
    --location eastus \
    --admin-user myadmin \
    --admin-password 'SecurePassword123!' \
    --sku-name Standard_D2ds_v4 \
    --tier GeneralPurpose \
    --high-availability SameZone

Understanding Failover

import mysql.connector
from mysql.connector import Error
import time

def connect_with_retry(max_retries=5, retry_delay=5):
    """Connection logic that handles failover"""
    config = {
        'host': 'myhaserver.mysql.database.azure.com',
        'database': 'mydb',
        'user': 'myadmin',
        'password': 'SecurePassword123!',
        'ssl_ca': '/path/to/DigiCertGlobalRootCA.crt.pem',
        'connection_timeout': 10,
        'autocommit': True
    }

    for attempt in range(max_retries):
        try:
            connection = mysql.connector.connect(**config)
            print(f"Connected successfully on attempt {attempt + 1}")
            return connection
        except Error as e:
            print(f"Attempt {attempt + 1} failed: {e}")
            if attempt < max_retries - 1:
                time.sleep(retry_delay)

    raise Exception("Failed to connect after all retries")

def execute_with_failover_handling(connection, query, params=None):
    """Execute query with automatic reconnection on failover"""
    max_retries = 3

    for attempt in range(max_retries):
        try:
            cursor = connection.cursor()
            cursor.execute(query, params)
            return cursor.fetchall()
        except mysql.connector.errors.OperationalError as e:
            if e.errno in (2006, 2013):  # Server gone away, Lost connection
                print(f"Connection lost, reconnecting... (attempt {attempt + 1})")
                connection = connect_with_retry()
            else:
                raise

    raise Exception("Query failed after all retries")

Monitoring HA Status

# Check HA status
az mysql flexible-server show \
    --resource-group myResourceGroup \
    --name myhaserver \
    --query "{name:name, haState:highAvailability.state, haMode:highAvailability.mode}"

# View HA events in activity log
az monitor activity-log list \
    --resource-group myResourceGroup \
    --query "[?contains(operationName.value, 'failover')]"

Planned Failover Testing

# Initiate a planned failover to test your application
az mysql flexible-server restart \
    --resource-group myResourceGroup \
    --name myhaserver \
    --failover Planned

Connection String Best Practices

# Use connection pooling for resilience
from mysql.connector import pooling

db_pool = pooling.MySQLConnectionPool(
    pool_name="mypool",
    pool_size=5,
    pool_reset_session=True,
    host='myhaserver.mysql.database.azure.com',
    database='mydb',
    user='myadmin',
    password='SecurePassword123!',
    ssl_ca='/path/to/DigiCertGlobalRootCA.crt.pem'
)

def get_connection():
    """Get a connection from the pool"""
    return db_pool.get_connection()

def execute_query(query):
    """Execute query using pooled connection"""
    conn = None
    try:
        conn = get_connection()
        cursor = conn.cursor()
        cursor.execute(query)
        return cursor.fetchall()
    finally:
        if conn:
            conn.close()  # Returns to pool

Application-Level Health Checks

from flask import Flask, jsonify
import mysql.connector

app = Flask(__name__)

@app.route('/health/db')
def db_health():
    """Database health check endpoint"""
    try:
        conn = mysql.connector.connect(
            host='myhaserver.mysql.database.azure.com',
            database='mydb',
            user='myadmin',
            password='SecurePassword123!',
            connection_timeout=5
        )
        cursor = conn.cursor()
        cursor.execute("SELECT 1")
        cursor.fetchone()
        conn.close()

        return jsonify({"status": "healthy", "database": "connected"}), 200
    except Exception as e:
        return jsonify({"status": "unhealthy", "error": str(e)}), 503

Implementing these HA patterns ensures your MySQL applications remain resilient during infrastructure failures.

Michael John Peña

Michael John Peña

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.