Azure Database for MySQL: Fix Setup & Config Errors
Why This Is Happening
So you spun up an Azure Database for MySQL instance and now something's broken. Maybe your app can't connect. Maybe high availability is acting weird. Maybe your costs are higher than expected, or your server just won't scale the way you thought it would. I've been in that exact spot, and I can tell you , the problem almost always comes down to one of three things: the wrong deployment configuration, misunderstood networking rules, or a mismatch between the compute tier you picked and the workload you're actually running.
Here's the thing Microsoft's error messages won't tell you upfront: Azure Database for MySQL - Flexible Server is a fundamentally different product from the older Single Server deployment model. If you're migrating from Single Server or following outdated documentation, you will hit walls. The Flexible Server model gives you a lot more control , custom maintenance windows, granular configuration settings, multiple availability zone options, but that flexibility means there are more ways to misconfigure it.
The three compute tiers are one of the biggest sources of confusion I see. You have Burstable, General Purpose, and Business Critical. Many developers default to Burstable because it's cheap and fast to spin up, then wonder why their production app chokes under concurrent load. Burstable instances are genuinely good for dev/test environments and low-concurrency workloads, but they are not built for sustained high traffic. If your MySQL queries are timing out under real user load, this is very likely your root cause.
High availability settings are another common culprit. The difference between Zone-redundant HA and Local-redundant HA matters enormously depending on what Azure region you're in and what your latency tolerance is. Zone-redundant HA gives you the highest protection against availability zone failures, but it's only available in regions that actually support multiple availability zones and zone-redundant premium file shares. If you picked that option in a region that doesn't support it, Azure will either error out or silently fall back, and you won't know your HA is compromised until an outage hits.
Connectivity errors are their own category entirely. Azure Database for MySQL uses SSL enforcement by default, firewall rules that don't always behave intuitively, and Virtual Network (VNet) integration that adds another layer of configuration most tutorials skip. If your connection string looks right but you're still getting "Access denied" or timeout errors, the firewall and SSL config are the first places I'd look.
I know this is frustrating, especially when it's blocking a production deployment or costing you real money on a misconfigured instance. But the good news is that every one of these issues has a clear fix path. Browse all Microsoft fix guides →
The Quick Fix, Try This First
Before you go deep into diagnostics, run through this fast triage checklist. It catches the majority of Azure Database for MySQL issues in under ten minutes.
Step 1: Check your server status in the Azure portal. Go to portal.azure.com, navigate to your Azure Database for MySQL - Flexible Server resource, and look at the top of the Overview blade. The server status should read "Available". If it says "Stopped", that's your entire problem right there, Azure lets you stop Flexible Servers to save costs, and they don't restart automatically on incoming connections. Hit the Start button at the top of the blade and wait about 60–90 seconds.
Step 2: Check firewall rules. In the left menu of your MySQL server resource, click Networking. You'll see your firewall rules. If your client IP isn't in that list, or if the rule is scoped too narrowly, your connections will be refused at the network layer before MySQL even sees them. Add your current IP. If you're connecting from an Azure service like App Service or AKS, make sure "Allow public access from any Azure service within Azure to this server" is toggled on, or configure the proper VNet rules.
Step 3: Verify SSL configuration. Azure Database for MySQL enforces SSL by default. If your connection string doesn't include SSL parameters, you'll get a cryptic error that looks like a credentials problem but isn't. For PHP, you need MYSQLI_CLIENT_SSL. For Python (mysql-connector-python), you need ssl_ca pointing to the DigiCert root certificate. For MySQL Workbench, go to Connection → SSL tab and set Use SSL to "Required".
Step 4: Confirm the admin username format. This trips people up constantly. In Flexible Server, the admin username is just the plain username you set, for example, myadmin. In the older Single Server model it was myadmin@servername. If you're using the old format on a Flexible Server, authentication will fail every time.
If all four of those check out and you're still having issues, move into the step-by-step guide below.
require_secure_transport. If you need to temporarily disable SSL enforcement for local testing, you can set it to OFF here, but never leave it off in production. The setting takes effect within about 60 seconds without a server restart.
If you're setting up Azure Database for MySQL for the first time, or if you think a bad initial configuration is your problem, the cleanest path is to understand exactly what you're configuring during provisioning. Mistakes made here cascade into everything downstream.
In the Azure portal, click Create a resource, search for "Azure Database for MySQL", and choose Flexible Server, not the deprecated Single Server option. On the Basics tab, you'll choose your subscription, resource group, server name, and region first.
Region choice matters. Not every Azure region supports zone-redundant high availability. If that feature is important to you, check the region list before picking your region, you can't change it after the server is created without a full migration. Similarly, if you plan to use VNet integration, pick a region where your other resources (App Service, AKS cluster, etc.) already live.
For the compute tier, be honest with yourself about your workload. Here's a practical breakdown:
- Burstable (e.g., Standard_B1ms): Good for dev environments, staging servers, internal tools with light traffic. The free 12-month Azure account offer covers 750 hours per month of Standard_B1ms, which is enough to run it continuously.
- General Purpose: The right tier for most production web applications with moderate to high concurrency.
- Business Critical: Memory-optimized workloads, high-transaction OLTP systems, analytics with heavy in-memory operations.
After creation, verify it worked: the Overview blade should show Status: Available, and the fully qualified server name will be in the format yourservername.mysql.database.azure.com. Test a connection with the MySQL CLI:
mysql -h yourservername.mysql.database.azure.com \
-u myadmin \
-p \
--ssl-mode=REQUIRED
If you connect successfully and see the MySQL prompt, your server is provisioned correctly. If not, move to the next step.
High availability configuration for Azure Database for MySQL - Flexible Server is where I see some of the most painful misconfigurations. People think they've turned on HA and discover during an actual incident that their standby replica isn't where they expected it to be, or doesn't exist at all.
In the Azure portal, go to your Flexible Server resource and click High Availability in the left menu. You'll see two options: Zone Redundant and Same Zone (which is Local-redundant HA).
Zone-redundant HA is the stronger option. When you enable it, Azure automatically provisions a standby replica in a different availability zone from your primary server. If the primary zone goes down, Azure fails over to the standby automatically, and your data stays intact because committed transactions are synchronously replicated. The tradeoff is latency: writes have to reach both zones before they're acknowledged. This is the right choice if your region supports multiple availability zones and your application can tolerate slightly higher write latency in exchange for the highest possible uptime.
Local-redundant HA (Same Zone) keeps both primary and standby in the same availability zone. This eliminates the cross-zone latency penalty and is available in every region where you can create a Flexible Server instance. It protects against hardware failures and unexpected restarts, but it won't save you if the entire availability zone goes down. For most small-to-medium production workloads, this is a sensible and more affordable choice.
One critical thing: when HA is enabled, you're billed for both the primary server compute/storage and the standby replica's compute/storage. I've seen teams turn on zone-redundant HA on a Business Critical tier for a dev environment and then wonder why their Azure bill doubled. Always check your compute tier before enabling HA in any environment.
To verify HA is configured and healthy, look at the High Availability blade. The Standby availability zone field should show an actual zone number (or "Same zone"), and the HA State should read "Healthy". If it says "Not enabled" after you thought you turned it on, check whether your region actually supports the option you selected.
Connectivity issues with Azure Database for MySQL are almost always caused by one of four things: firewall rules, SSL requirements, wrong username format, or a server that's been stopped. We touched on the quick check earlier, here's how to dig deeper when the surface-level fixes don't work.
Firewall rules for public access: If your server is using Public Access networking, every client IP that needs to connect must be explicitly allowed. Go to Networking in the portal, click Add current client IP address to allow your current machine, or add a rule manually. If you're getting connection refused from an Azure App Service, go to your App Service and find its outbound IP addresses (under Properties → Outbound IP Addresses), then add each of those to the MySQL firewall rules.
VNet-integrated servers: If you chose Private Access during server creation, the server is entirely VNet-integrated and has no public IP. You can only connect from within the same VNet or a peered VNet. If your client app isn't in the same VNet, you'll get a straight connection timeout, which looks identical to a firewall block from the client side. Fix this by either adding your app to the VNet, setting up VNet peering, or using an Azure Bastion jump server for direct DB access.
SSL certificate issues: Azure Database for MySQL requires connections to use TLS. Download the DigiCert Global Root CA certificate and reference it in your connection. For Python:
import mysql.connector
conn = mysql.connector.connect(
host="yourserver.mysql.database.azure.com",
user="myadmin",
password="yourpassword",
database="yourdatabase",
ssl_ca="/path/to/DigiCertGlobalRootCA.crt.pem",
ssl_verify_cert=True
)
Username format reminder: On Flexible Server, your admin login is just myadmin. On the old Single Server it was myadmin@servername. If you migrated from Single Server, update every connection string in your application.
After making firewall changes, wait about 30 seconds for the rules to propagate, then retry. If connection still fails, use the Connect blade in the Azure portal, it shows you a test connection status and sometimes gives a more specific error than the MySQL client does.
One of the most common issues I see with Azure Database for MySQL - Flexible Server is performance degradation that isn't really a MySQL problem, it's a compute tier problem. The server is doing its job fine; it's just not getting enough CPU or memory for what you're asking it to do.
Flexible Server makes this easy to fix without downtime. In the portal, go to Compute + storage in the left menu. Here you can change both the compute tier and the specific VM size within a tier. The change usually takes 1–2 minutes and involves a brief failover if HA is enabled.
How do you know which tier you actually need? Check these signals:
- CPU consistently above 80%: You're on the wrong tier or wrong VM size. Move up a tier or increase vCores.
- Memory pressure / OOM errors: Move to a memory-optimized Business Critical SKU, or look at your
innodb_buffer_pool_sizesetting under Server parameters. - Burstable tier running out of credits: When a B-series VM exhausts its CPU credits, performance craters. This shows up in Azure Monitor as CPU Credit Remaining dropping to zero. If this is happening in production, move to General Purpose immediately.
The Burstable tier earns CPU credits when the server is idle and burns them during bursts of activity. That's fine for sporadic workloads. But if your database is handling sustained traffic, say, 20+ concurrent connections doing real queries, it will run out of credits and become painfully slow. This is the single most common cause of "my Azure MySQL was fine yesterday and terrible today" reports.
To scale storage, you can increase it from the same Compute + storage blade. Note that storage can only be scaled up, not down. Azure also offers auto-grow for storage, enable this if you don't want to manually monitor disk space. When auto-grow is on, Azure automatically increases your storage size when it gets close to the limit, preventing the server from going read-only due to full disk.
After scaling, test query performance with a few representative queries from your application. If you have slow query logging enabled (set slow_query_log = ON in Server parameters), check those logs to spot which queries are still lagging.
Azure Database for MySQL - Flexible Server handles backups and patching automatically, but there are configuration choices that determine whether those automated processes cause you problems or prevent them.
Backup retention: By default, Flexible Server keeps automated backups for 7 days. You can configure this up to 35 days. To change it, go to Compute + storage → Backup section, and adjust the Backup retention period slider. Longer retention means you have more point-in-time restore options if data gets corrupted or accidentally deleted, which is a very real scenario when someone runs a bad migration or a buggy deployment script.
Point-in-time restore: If you need to recover from a mistake, go to your server's Overview blade and click Restore at the top. You'll specify a restore point (any time within your retention window) and a new server name, Azure spins up a new server at that point in time, leaving your existing server intact. You can then verify the restored data and either use it directly or selectively export what you need.
Maintenance windows: By default, Azure may apply OS and database engine patches at any time during a system-managed maintenance window. That's fine for dev environments. For production, you want control. Go to Maintenance in the left menu and switch from "System managed" to "Custom schedule". Pick a day and time that corresponds to your lowest-traffic period, typically early morning on a weekend.
Automated patching covers the underlying hardware, operating system, and the MySQL engine itself. You don't need to apply MySQL security patches manually, Azure handles that. What the maintenance window controls is when that work happens. On Flexible Server with HA enabled, patches are applied to the standby replica first, then a failover occurs, and then the original primary gets patched. The downtime during failover is typically 60–120 seconds.
After setting your maintenance window: You'll receive Azure Service Health notifications before any maintenance happens, make sure your subscription's health alerts are configured so these go to someone who actually checks them. Go to Monitor → Service Health → Health Alerts to set this up.
Advanced Troubleshooting
Once you've worked through the standard fixes, some Azure Database for MySQL problems require digging deeper into diagnostics, enterprise networking, and platform-level controls.
Diagnosing with Azure Monitor and Diagnostic Logs
Azure Monitor is your best friend for understanding what's actually happening inside your Flexible Server instance. Go to your MySQL resource and click Monitoring → Metrics. The metrics that matter most for performance diagnosis:
CPU percent, consistent values above 80% indicate under-provisioned computeMemory percent, high memory pressure causes InnoDB to constantly evict buffer pool pages, killing query performanceStorage used, watch this if auto-grow is off; full disk puts the server in read-only modeActive connections, if this is near yourmax_connectionslimit, new connections will be refused with error "Too many connections"CPU Credits Remaining(Burstable tier only), if this hits zero, your server is being throttled
For deeper logs, go to Monitoring → Diagnostic settings and add a diagnostic setting that sends logs to Log Analytics workspace, storage account, or Event Hubs. The most useful log categories are MySqlSlowLogs (slow query log) and MySqlAuditLogs (connection and query auditing).
Once slow query logs are flowing to Log Analytics, you can query them with KQL:
AzureDiagnostics
| where Category == "MySqlSlowLogs"
| where query_time_d > 2.0
| project TimeGenerated, query_time_d, sql_text_s, host_s
| order by query_time_d desc
| take 50
This surfaces the 50 slowest queries in the last period. That list tells you exactly where to add indexes or rewrite query logic.
Server Parameters That Actually Matter
Azure Database for MySQL - Flexible Server gives you access to most MySQL server parameters directly through the portal. Go to Server parameters in the left menu and search for these high-impact settings:
innodb_buffer_pool_size: Should be 50–70% of available RAM on dedicated production servers. The default is often too low.max_connections: Default is often 151. For production applications with connection pooling, you may need to raise this, but every connection uses memory, so don't just set it to 10,000 without thinking.slow_query_log: Set to ON for production. Setlong_query_timeto 1 or 2 seconds to catch problem queries.wait_timeoutandinteractive_timeout: If your app uses persistent connections and you're seeing "MySQL server has gone away" errors, these are likely too short for your connection pool's idle timeout settings.
Migration Errors from Single Server or Amazon RDS
If you migrated to Flexible Server from Single Server or from Amazon RDS for MySQL, several categories of errors show up post-migration. Character set mismatches are common, if the source had tables in latin1 and the target defaults to utf8mb4, string comparison behavior changes and some queries break. Check with:
SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';
Time zone data can also cause issues. Azure Database for MySQL - Flexible Server supports time zone settings via the time_zone server parameter, but the time zone tables need to be populated. Run the MySQL Workbench time zone import or use the mysql_tzinfo_to_sql utility against your Flexible Server if you're getting errors from functions like CONVERT_TZ().
Replication Latency Issues
If you're using data-in replication (for example, replicating from on-premises or from Amazon RDS), replication latency is a common pain point. The most frequent causes are large transactions, missing indexes on the replica, and DDL statements that lock tables. Monitor replication lag with:
SHOW SLAVE STATUS\G
Look at the Seconds_Behind_Master value. Anything above a few seconds for sustained periods indicates a replication performance problem worth addressing.
If you're seeing errors that reference internal Azure fabric errors (typically 5-digit codes like "Error 40197" or "Error 40613"), your server is experiencing a platform-level event outside your control. These are transient failures during Azure infrastructure maintenance or failover operations. Your application should implement retry logic with exponential backoff, but if these errors persist for more than 30 minutes without recovery, open a support ticket. Similarly, if point-in-time restore fails, if your HA standby is stuck in an unhealthy state, or if you have a data loss scenario, escalate immediately to Microsoft Support. These aren't situations to debug yourself, they require backend platform access you don't have.
Prevention & Best Practices
Most of the Azure Database for MySQL problems I've described in this guide are entirely preventable. The hard part isn't fixing them, it's building the habits and configurations that stop them from happening in the first place.
Right-size from the start. The time to think carefully about compute tier is during provisioning, not after an outage. If you know your application has real concurrent traffic, start on General Purpose rather than Burstable and scale down later if metrics show you're over-provisioned. Scaling down is possible; recovering from a production outage caused by credit exhaustion is much more expensive in real terms.
Enable storage auto-grow. There is almost no reason not to enable this. A full disk puts your MySQL server in read-only mode, which means your application starts throwing errors immediately. Auto-grow prevents that scenario automatically. The cost of a few extra gigabytes of Azure storage is trivial compared to an unplanned outage.
Use connection pooling. Every time your application opens and closes a MySQL connection, there's overhead. At scale, this kills performance. Use a connection pooler, ProxySQL is popular for MySQL workloads, and if you're on .NET or Java, use the built-in connection pool in your database driver. Set wait_timeout in MySQL to match your pooler's idle timeout so connections don't go stale.
Test your HA failover before you need it. Azure gives you the ability to trigger a manual failover from the portal (High Availability → Forced Failover). Do this in a staging environment and verify that your application reconnects automatically within an acceptable time window. If your app doesn't handle the 60–120 second failover period correctly, fix that before it happens in production under pressure.
Set backup retention to at least 14 days in production. The default 7 days sounds like a lot until someone runs a bad data migration on a Thursday and doesn't notice until the following Monday. With 7-day retention, you'd have almost no margin. 14–35 days gives you real recovery options.
Tag your resources and set cost alerts. Azure Database for MySQL compute and storage costs add up quickly, especially if you forget to stop dev servers or accidentally enable HA on a non-production instance. Set Azure Cost Management budget alerts so you get an email if spending exceeds your expected threshold for the month.
- Enable slow query logging on production servers and review it weekly, most performance regressions show up here first
- Set a custom maintenance window during your lowest-traffic hours to control when patch reboots happen
- Use the Azure free account offer to run a Burstable Standard_B1ms instance for development at zero cost for the first 12 months
- Configure Azure Monitor alerts on CPU percent (threshold: 80%) and active connections (threshold: 80% of max_connections) to get early warnings before issues become outages
Frequently Asked Questions
What is Azure Database for MySQL - Flexible Server and how is it different from Single Server?
Azure Database for MySQL - Flexible Server is the current, actively developed deployment model for MySQL on Azure. It's a fully managed relational database service based on MySQL Community Edition (versions 5.7 and 8.0) that gives you much more control than the old Single Server model, including custom maintenance windows, granular server parameter tuning, zone-redundant or local-redundant HA options, and the ability to stop and start the server to save costs. Single Server is being retired, so if you're still on it, migration to Flexible Server is the right path forward. The username format also changes: Flexible Server uses myadmin instead of myadmin@servername, which breaks connection strings if you don't update them.
How do I get started with Azure Database for MySQL for free?
If you have an Azure free account, you get 12 months of Azure Database for MySQL - Flexible Server usage at no charge. The free offer covers up to 750 hours per month on a Burstable Standard_B1ms virtual machine, that's enough to run one instance continuously every month, plus 32 GB of storage and 32 GB of backup storage. To use it, create a new Flexible Server from the Azure portal and select the free offer option during provisioning. Note that the free tier is specifically the Burstable Standard_B1ms size, so if you pick a larger instance or a different tier, normal billing applies. It's a great way to build and test your application before committing to a paid production tier.
What's the difference between zone-redundant HA and local-redundant HA in Azure Database for MySQL?
Both options automatically provision a standby replica that can take over if the primary server has a problem, but they differ in where that standby lives. Zone-redundant HA places the standby in a completely different availability zone from the primary, giving you protection against an entire zone going down. It's the stronger option, but it's only available in Azure regions that support multiple availability zones, and writes are slightly slower because they have to be confirmed across zones. Local-redundant HA keeps primary and standby in the same availability zone, lower write latency, available in every region, but won't protect you if the whole zone goes offline. For most small and medium workloads, local-redundant HA is the right balance of protection and cost.
What's new in Azure Database for MySQL - Flexible Server recently?
Microsoft publishes ongoing updates to the Flexible Server feature set through the official Azure blog and the "What's new in Azure Database for MySQL" documentation page. Recent additions have included expanded region availability for zone-redundant HA, improved metrics and diagnostic logging in Azure Monitor, updates to supported MySQL minor versions (including 8.0.x patch releases), and enhanced performance on Business Critical compute tiers. The best way to stay current is to subscribe to the Azure updates RSS feed or follow the Azure Database for MySQL blog directly, Microsoft ships new capabilities frequently, and some of them (like new server parameter controls or improved backup options) can directly help with problems you might be working around today.
My Azure MySQL connection keeps timing out, what's wrong?
Timeout errors from Azure Database for MySQL - Flexible Server almost always trace back to one of these: a missing or incorrect firewall rule blocking your client IP, VNet integration that isolates the server from clients not inside the virtual network, an SSL mismatch where your connection string isn't specifying SSL parameters correctly, or a stopped server that needs to be manually restarted from the portal. Start by checking the server status in the portal Overview blade (it should say "Available"), then go to Networking and verify your client IP is in the firewall allow list. If the server is VNet-integrated (Private Access), you must connect from within the same VNet or a peered network, there's no public endpoint to connect to.
How do I reduce my Azure Database for MySQL costs without breaking my application?
Several strategies work well here without impacting production reliability. First, stop dev and staging servers when they're not in use, Flexible Server lets you stop the server from the portal and you're only billed for storage while it's stopped, not compute. Second, right-size your compute tier: if Azure Monitor shows your CPU and memory are consistently under 40% utilization, you're likely over-provisioned and can move to a smaller VM size within the same tier. Third, consider reserved instances for production servers with predictable compute needs, Microsoft offers significant discounts (up to 37% or more) for 1-year or 3-year reservations compared to pay-as-you-go pricing. Fourth, review your backup retention period, longer retention means more backup storage costs, so only keep as many days as your recovery policy actually requires.