# Database for MySQL Flexible Server

Source: /azure/services/dbfor-mysql/

## Introduction

Azure Database for MySQL flexible server is a fully managed relational database service based on the MySQL community edition.
It gives granular control over database configuration through server parameters, offers Burstable, General Purpose and Business Critical compute tiers, and adds features such as high availability, read replicas and automated backups.
For more information, see [What is Azure Database for MySQL - Flexible Server?](https://learn.microsoft.com/en-us/azure/mysql/flexible-server/overview).

LocalStack for Azure provides a local environment for building and testing applications that make use of Azure Database for MySQL.
Each flexible server is backed by a real MySQL instance that your applications can connect to.
The supported APIs are available on our [API Coverage section](#api-coverage), which provides information on the extent of Database for MySQL's integration with LocalStack.

## Getting started

This guide is designed for users new to Azure Database for MySQL and assumes basic knowledge of the Azure CLI and our `lstk az` proxy.

Launch LocalStack using your preferred method. For more information, see [Introduction to LocalStack for Azure](/azure/getting-started/). Once the container is running, enable Azure CLI interception by running:

```bash
lstk az start-interception
```

This command points the `az` CLI away from the public Azure management REST API and toward the LocalStack for Azure emulator API.
To revert this configuration, run:

```bash
lstk az stop-interception
```

This reconfigures the `az` CLI to send commands to the official Azure management REST API.

### Create a resource group

Create a resource group to hold all resources created in this guide:

```bash
az group create \
  --name rg-mysql-demo \
  --location westeurope
```

```bash title="Output"
{
  "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-mysql-demo",
  "location": "westeurope",
  "name": "rg-mysql-demo",
  "properties": {
    "provisioningState": "Succeeded"
  },
  ...
}
```

### Create a flexible server

Create a Burstable-tier MySQL flexible server with 32 GB of storage:

```bash
az mysql flexible-server create \
  --name mysql-demo \
  --resource-group rg-mysql-demo \
  --location westeurope \
  --admin-user mysqladmin \
  --admin-password 'P@ssw0rd2024!' \
  --sku-name Standard_B1ms \
  --tier Burstable \
  --version 8.0.21 \
  --storage-size 32 \
  --yes
```

The command waits until the server is ready. Besides the server, the Azure CLI creates a database named `flexibleserverdb` and a firewall rule for your client IP address:

```bash title="Output"
{
  "connectionString": "mysql flexibleserverdb --host mysql-demo.mysql.database.localhost.localstack.cloud:4511 --user mysqladmin --password=P@ssw0rd2024!",
  "databaseName": "flexibleserverdb",
  "host": "mysql-demo.mysql.database.localhost.localstack.cloud:4511",
  "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-mysql-demo/providers/Microsoft.DBforMySQL/flexibleServers/mysql-demo",
  "location": "westeurope",
  "password": "P@ssw0rd2024!",
  "resourceGroup": "rg-mysql-demo",
  "username": "mysqladmin",
  "version": "8.0.21",
  ...
}
```

The host name resolves to your machine, and the port after the colon is the one LocalStack assigned to this server.

### Show and list flexible servers

Retrieve the details of the flexible server:

```bash
az mysql flexible-server show \
  --name mysql-demo \
  --resource-group rg-mysql-demo
```

```bash title="Output"
{
  "administratorLogin": "mysqladmin",
  "availabilityZone": "1",
  "backup": {
    "backupIntervalHours": 24,
    "backupRetentionDays": 7,
    "geoRedundantBackup": "Disabled"
  },
  "fullyQualifiedDomainName": "mysql-demo.mysql.database.localhost.localstack.cloud:4511",
  "highAvailability": {
    "mode": "Disabled",
    "state": "NotEnabled",
    ...
  },
  "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-mysql-demo/providers/Microsoft.DBforMySQL/flexibleServers/mysql-demo",
  "location": "westeurope",
  "name": "mysql-demo",
  "network": {
    "publicNetworkAccess": "Enabled",
    ...
  },
  "resourceGroup": "rg-mysql-demo",
  "sku": {
    "name": "Standard_B1ms",
    "tier": "Burstable"
  },
  "state": "Ready",
  "storage": {
    "autoGrow": "Enabled",
    "iops": 396,
    "storageSizeGb": 32,
    "storageSku": "Premium_LRS",
    ...
  },
  "type": "Microsoft.DBforMySQL/flexibleServers",
  "version": "8.0.21",
  ...
}
```

Then list all flexible servers in the resource group:

```bash
az mysql flexible-server list \
  --resource-group rg-mysql-demo \
  --output table
```

```bash title="Output"
Name        Resource Group    Location    Version    Storage Size(GiB)    Tier       SKU            State    HA State    Availability zone
----------  ----------------  ----------  ---------  -------------------  ---------  -------------  -------  ----------  -------------------
mysql-demo  rg-mysql-demo     westeurope  8.0.21     32                   Burstable  Standard_B1ms  Ready    NotEnabled  1
```

### Connect to the server

Connect with any MySQL client, using the host and port from `fullyQualifiedDomainName`.
LocalStack assigns the port when it creates the server, so read it from the server rather than copying it from this guide.
TLS is required by default, as on Azure:

```bash
FQDN=$(az mysql flexible-server show \
  --name mysql-demo \
  --resource-group rg-mysql-demo \
  --query fullyQualifiedDomainName \
  --output tsv)

mysql \
  --host "${FQDN%:*}" \
  --port "${FQDN##*:}" \
  --user mysqladmin \
  --password='P@ssw0rd2024!' \
  --ssl-mode=REQUIRED \
  -e "SELECT VERSION(); SHOW DATABASES;"
```

```bash title="Output"
VERSION()
8.0.46
Database
flexibleserverdb
information_schema
mysql
performance_schema
sys
```

### Update a flexible server

Update the server SKU and storage size:

```bash
az mysql flexible-server update \
  --name mysql-demo \
  --resource-group rg-mysql-demo \
  --sku-name Standard_B2s \
  --tier Burstable \
  --storage-size 64
```

Then check the new SKU and storage size:

```bash
az mysql flexible-server show \
  --name mysql-demo \
  --resource-group rg-mysql-demo \
  --query "{sku:sku,storageSizeGb:storage.storageSizeGb}"
```

```bash title="Output"
{
  "sku": {
    "name": "Standard_B2s",
    "tier": "Burstable"
  },
  "storageSizeGb": 64
}
```

### Create a database

Create a database on the flexible server, then list the databases:

```bash
az mysql flexible-server db create \
  --server-name mysql-demo \
  --resource-group rg-mysql-demo \
  --database-name sampledb

az mysql flexible-server db list \
  --server-name mysql-demo \
  --resource-group rg-mysql-demo \
  --output table
```

```bash title="Output"
Name              ResourceGroup
----------------  ---------------
flexibleserverdb  rg-mysql-demo
sampledb          rg-mysql-demo
```

The database is created in the MySQL instance, so it is also visible to a MySQL client.

### Create a firewall rule

Create a firewall rule that allows a range of client IP addresses:

```bash
az mysql flexible-server firewall-rule create \
  --resource-group rg-mysql-demo \
  --name mysql-demo \
  --rule-name allow-office \
  --start-ip-address 203.0.113.10 \
  --end-ip-address 203.0.113.20
```

```bash title="Output"
{
  "endIpAddress": "203.0.113.20",
  "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-mysql-demo/providers/Microsoft.DBforMySQL/flexibleServers/mysql-demo/firewallRules/allow-office",
  "name": "allow-office",
  "resourceGroup": "rg-mysql-demo",
  "startIpAddress": "203.0.113.10",
  "type": "Microsoft.DBforMySQL/flexibleServers/firewallRules",
  ...
}
```

### View and update server parameters

View the current value of the `wait_timeout` server parameter:

```bash
az mysql flexible-server parameter show \
  --resource-group rg-mysql-demo \
  --server-name mysql-demo \
  --name wait_timeout
```

```bash title="Output"
{
  "allowedValues": "1-31536000",
  "currentValue": "28800",
  "dataType": "Integer",
  "defaultValue": "28800",
  "description": "The number of seconds the server waits for activity on a noninteractive connection before closing it.",
  "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-mysql-demo/providers/Microsoft.DBforMySQL/flexibleServers/mysql-demo/configurations/wait_timeout",
  "isConfigPendingRestart": "False",
  "isDynamicConfig": "True",
  "isReadOnly": "False",
  "name": "wait_timeout",
  "source": "system-default",
  "type": "Microsoft.DBforMySQL/flexibleServers/configurations",
  "value": "28800",
  ...
}
```

Set it to 600 seconds:

```bash
az mysql flexible-server parameter set \
  --resource-group rg-mysql-demo \
  --server-name mysql-demo \
  --name wait_timeout \
  --value 600
```

```bash title="Output"
{
  "allowedValues": "1-31536000",
  "dataType": "Integer",
  "defaultValue": "28800",
  "isConfigPendingRestart": "False",
  "isDynamicConfig": "True",
  "name": "wait_timeout",
  "source": "user-override",
  "type": "Microsoft.DBforMySQL/flexibleServers/configurations",
  "value": "600",
  ...
}
```

Dynamic parameters such as `wait_timeout` are applied to the running MySQL instance straight away, so `SELECT @@global.wait_timeout` now returns `600`.

### Stop, start, and restart a server

Stop the flexible server:

```bash
az mysql flexible-server stop \
  --resource-group rg-mysql-demo \
  --name mysql-demo
```

Verify the server state is `Stopped`:

```bash
az mysql flexible-server show \
  --resource-group rg-mysql-demo \
  --name mysql-demo \
  --query state \
  --output tsv
```

```bash title="Output"
Stopped
```

Start the server again, and restart it:

```bash
az mysql flexible-server start \
  --resource-group rg-mysql-demo \
  --name mysql-demo

az mysql flexible-server restart \
  --resource-group rg-mysql-demo \
  --name mysql-demo
```

### Delete and verify

Delete the flexible server, then list the flexible servers to confirm the resource group is now empty:

```bash
az mysql flexible-server delete \
  --resource-group rg-mysql-demo \
  --name mysql-demo \
  --yes

az mysql flexible-server list \
  --resource-group rg-mysql-demo
```

```bash title="Output"
[]
```

## Features

The MySQL Flexible Server emulator supports the following features:

- **Real MySQL instances**: Each flexible server runs a MySQL container, and the server's administrator login and password work for client connections. TLS is required by default (`require_secure_transport`).
- **Server lifecycle management**: Create, get, update, list, and delete flexible servers, including password changes for the administrator login.
- **Databases**: Create, get, list, and delete databases. Each database is created in the MySQL instance.
- **Server parameters**: Get, list, and update server parameters with validation against their allowed values. Dynamic parameters are applied to the running instance immediately.
- **Firewall rules**: Create, get, update, list, and delete IP-based firewall rules.
- **Log files**: List and download the slow query log, which appears once you set the `slow_query_log` parameter to `ON` and `log_output` to `FILE`.
- **SKU and version validation**: The tier must match the SKU (`Burstable` for `Standard_B*`, `GeneralPurpose` for `Standard_D*`, `MemoryOptimized` for `Standard_E*`), and the server version must be 5.7, 8.0.21, 8.4 or 9.5.
- **Name availability and capabilities**: Check server name availability, and query the SKUs, storage sizes and versions offered in a location.
- **Stop, start, and restart**: Transition servers between the `Ready` and `Stopped` states.

## Configuration

| Environment variable | Default | Description |
| --- | --- | --- |
| `LS_AZURE_MYSQL_FLEXIBLE_IMAGE_TAG` | `8.0` | Tag of the `mysql` Docker image that backs every flexible server. |

## Limitations

- **One MySQL version**: Every server runs the image selected by `LS_AZURE_MYSQL_FLEXIBLE_IMAGE_TAG`, whatever `version` you request. The requested version is stored and returned.
- **Stop, start and restart are state changes**: The MySQL container keeps running while a server is `Stopped`, and a restart does not restart it, so static parameters changed after creation do not take effect.
- **Database character set and collation with the Azure CLI**: The `--charset` and `--collation` options of `az mysql flexible-server db create` are not applied, and the database is created with the instance's defaults. Requests that set `charset` and `collation` under the database's `properties`, as ARM templates and `az rest` do, are applied.
- **Firewall rules are not enforced**: Firewall rules are stored and returned, but every client that can reach the port can connect.
- **High availability, backups and networking are not emulated**: High availability, storage auto-grow, backup retention, maintenance windows, Microsoft Entra administrators and virtual network integration are stored but have no effect. `az mysql flexible-server restart --failover` is accepted and does nothing beyond a restart; the failover operation itself requires high availability, which Burstable servers cannot enable.
- **Replicas and restores start empty**: Creating a read replica or a point-in-time restore creates a new server with the source's administrator login, version, SKU, storage and backup settings, but without its data, databases, server parameters or firewall rules. Geo-restore is not supported.
- **No data persistence**: The MySQL data is not persisted and is lost when the emulator is stopped or restarted.

## API Coverage


### Database for MySQL Flexible Server API coverage

Source service: `dbfor-mysql`. 55 of 64 tracked operations are implemented.

Service documentation: /azure/services/dbfor-mysql/

| Operation | Status |
| --- | --- |
| CheckNameAvailability.Execute | Implemented |
| CheckNameAvailabilityWithoutLocation.Execute | Implemented |
| CheckVirtualNetworkSubnetUsage.Execute | Not implemented |
| FlexibleServers.AdvancedThreatProtectionSettings_Get | Implemented |
| FlexibleServers.AdvancedThreatProtectionSettings_List | Implemented |
| FlexibleServers.AdvancedThreatProtectionSettings_Update | Implemented |
| FlexibleServers.AdvancedThreatProtectionSettings_UpdatePut | Implemented |
| FlexibleServers.AzureAdAdministrators_CreateOrUpdate | Implemented |
| FlexibleServers.AzureAdAdministrators_Delete | Implemented |
| FlexibleServers.AzureAdAdministrators_Get | Implemented |
| FlexibleServers.AzureAdAdministrators_ListByServer | Implemented |
| FlexibleServers.BackupAndExport_Create | Not implemented |
| FlexibleServers.BackupAndExport_ValidateBackup | Not implemented |
| FlexibleServers.Backups_Get | Implemented |
| FlexibleServers.Backups_ListByServer | Implemented |
| FlexibleServers.Backups_Put | Implemented |
| FlexibleServers.Configurations_BatchUpdate | Implemented |
| FlexibleServers.Configurations_CreateOrUpdate | Implemented |
| FlexibleServers.Configurations_Get | Implemented |
| FlexibleServers.Configurations_ListByServer | Implemented |
| FlexibleServers.Configurations_Update | Implemented |
| FlexibleServers.Databases_CreateOrUpdate | Implemented |
| FlexibleServers.Databases_Delete | Implemented |
| FlexibleServers.Databases_Get | Implemented |
| FlexibleServers.Databases_ListByServer | Implemented |
| FlexibleServers.FirewallRules_CreateOrUpdate | Implemented |
| FlexibleServers.FirewallRules_Delete | Implemented |
| FlexibleServers.FirewallRules_Get | Implemented |
| FlexibleServers.FirewallRules_ListByServer | Implemented |
| FlexibleServers.LogFiles_ListByServer | Implemented |
| FlexibleServers.LongRunningBackup_Create | Implemented |
| FlexibleServers.LongRunningBackups_Get | Implemented |
| FlexibleServers.LongRunningBackups_List | Implemented |
| FlexibleServers.Maintenances_List | Implemented |
| FlexibleServers.Maintenances_Read | Implemented |
| FlexibleServers.Maintenances_Update | Implemented |
| FlexibleServers.PrivateEndpointConnections_CreateOrUpdate | Implemented |
| FlexibleServers.PrivateEndpointConnections_Delete | Implemented |
| FlexibleServers.PrivateEndpointConnections_Get | Implemented |
| FlexibleServers.PrivateEndpointConnections_ListByServer | Implemented |
| FlexibleServers.PrivateLinkResources_Get | Implemented |
| FlexibleServers.PrivateLinkResources_ListByServer | Implemented |
| FlexibleServers.Replicas_ListByServer | Implemented |
| FlexibleServers.ServersMigration_CutoverMigration | Not implemented |
| FlexibleServers.Servers_Create | Implemented |
| FlexibleServers.Servers_Delete | Implemented |
| FlexibleServers.Servers_DetachVNet | Implemented |
| FlexibleServers.Servers_Failover | Implemented |
| FlexibleServers.Servers_Get | Implemented |
| FlexibleServers.Servers_List | Implemented |
| FlexibleServers.Servers_ListByResourceGroup | Implemented |
| FlexibleServers.Servers_ResetGtid | Implemented |
| FlexibleServers.Servers_Restart | Implemented |
| FlexibleServers.Servers_Start | Implemented |
| FlexibleServers.Servers_Stop | Implemented |
| FlexibleServers.Servers_Update | Implemented |
| FlexibleServers.Servers_ValidateEstimateHighAvailability | Implemented |
| GetPrivateDnsZoneSuffix.Execute | Not implemented |
| LocationBasedCapabilities.List | Implemented |
| LocationBasedCapabilitySet.Get | Not implemented |
| LocationBasedCapabilitySet.List | Not implemented |
| OperationProgress.Get | Not implemented |
| OperationResults.Get | Implemented |
| Operations.List | Not implemented |
