Skip to main content
emnode
Compliance Medium severity MCSB IM-1

Microsoft Defender for Cloud · Azure Database for MySQL

Azure Database for MySQL should have a Microsoft Entra administrator provisioned

Written and reviewed by Emnode · Last reviewed

What does the recommendation "Azure Database for MySQL should have a Microsoft Entra administrator provisioned" check?

Flags any Azure Database for MySQL flexible server that has no Microsoft Entra administrator assigned, which means the server cannot authenticate users through Entra ID and falls back to local MySQL accounts secured by passwords alone. The check only confirms that an administrator principal (a user or group) is provisioned on the server; it does not verify that individual database logins actually use Entra authentication, that local password accounts have been removed, or that conditional access or MFA is enforced on the administrator. It applies to flexible servers and does not cover the retired single server deployment model. Note that only one Entra administrator, a user or a group, can be provisioned per server at a time, so the check is satisfied by a single correctly configured principal.

Why does "Azure Database for MySQL should have a Microsoft Entra administrator provisioned" matter?

Without an Entra administrator, every MySQL login is a standalone password that lives outside your identity platform: it is not covered by central offboarding, cannot be protected by conditional access or MFA, and keeps working long after a leaver loses their other access. Those credentials are commonly hard-coded in connection strings and config files, so a single leaked password gives an attacker a direct, unmonitored route to the database. Provisioning an Entra administrator lets you manage database access through the same directory, groups and lifecycle that govern the rest of your estate, so a disabled account loses database access at the same moment it loses everything else, and you gain Entra sign-in logs for the connections that matter most. It also opens the door to passwordless application access, where a workload connects with its own managed identity token instead of a stored secret, removing the credential from your codebase entirely.

How do I fix "Azure Database for MySQL should have a Microsoft Entra administrator provisioned"?

  1. Create a user-assigned managed identity for the server and grant it the three Microsoft Graph application permissions Entra authentication needs to read the directory, User.Read.All, GroupMember.Read.All and Application.Read.All (or assign it the Directory Readers role instead), then attach it so the server can resolve directory principals.
  2. Provision the administrator with 'az mysql flexible-server ad-admin create --resource-group <rg> --server-name <server> --display-name <user-or-group> --object-id <entra-object-id> --identity <managed-identity>', pointing it at a security group rather than a single person so access survives staff changes.
  3. Enforce it across the subscription with a flexible-server policy so new servers are caught. Look the definition up by its exact display name rather than hard-coding a GUID, then assign it: pid=$(az policy definition list --query "[?displayName=='Azure MySQL flexible server should have Microsoft Entra Only Authentication enabled'].name" -o tsv); az policy assignment create --name mysql-entra-only --policy "$pid" --scope /subscriptions/<sub-id>. This audits flexible servers that have not switched to Entra-only authentication, which requires an Entra administrator to be in place first.

Remediation script · bash

# 1. Lock the wire and the network on a production PostgreSQL flexible server.
RG=db-prod-rg
SRV=ordersprod-pg

# Enforce encrypted connections (dynamic, no restart needed).
az postgres flexible-server parameter set \
  --resource-group "$RG" --server-name "$SRV" \
  --source user-override \
  --name require_secure_transport --value ON

# Pin the minimum TLS version.
az postgres flexible-server parameter set \
  --resource-group "$RG" --server-name "$SRV" \
  --source user-override \
  --name ssl_min_protocol_version --value TLSv1.2

# Disable public network access.
az postgres flexible-server update \
  --resource-group "$RG" --name "$SRV" \
  --public-access Disabled

# 2. Turn on the pgaudit trail and connection throttling.
for p in "pgaudit.log=role,ddl,misc" \
         "pgaudit.log_client=ON" \
         "pgaudit.log_level=log" \
         "pgaudit.log_statement=on" \
         "pgaudit.log_statement_once=on" \
         "connection_throttle.enable=on"; do
  az postgres flexible-server parameter set \
    --resource-group "$RG" --server-name "$SRV" \
    --source user-override \
    --name "${p%%=*}" --value "${p#*=}"
done

# 3. Provision a Microsoft Entra administrator and disable password sign-in.
az postgres flexible-server ad-admin create \
  --resource-group "$RG" --server-name "$SRV" \
  --display-name "dba-team" \
  --object-id "$(az ad group show --group dba-team --query id -o tsv)" \
  --type Group
az postgres flexible-server update \
  --resource-group "$RG" --name "$SRV" \
  --microsoft-entra-auth Enabled --password-auth Disabled

# 4. Ratchet it shut: deny any future PostgreSQL flexible server with public access.
# Look the built-in policy up by its EXACT display name, never paste a guessed GUID.
PID=$(az policy definition list \
  --query "[?displayName=='Public network access should be disabled for PostgreSQL flexible servers'].name" \
  -o tsv)
az policy assignment create \
  --name deny-public-pg-flex \
  --policy "$PID" \
  --params '{"effect":{"value":"Deny"}}' \
  --scope "/subscriptions/00000000-0000-0000-0000-000000000000"

Full walkthrough (console steps, edge cases and verification) in the lesson Harden Azure MySQL and PostgreSQL.

Is "Azure Database for MySQL should have a Microsoft Entra administrator provisioned" a false positive?

A flexible server that is being decommissioned, or one used only for a short-lived migration staging copy that is firewalled off and scheduled for deletion, can legitimately run without an Entra administrator. Exempt it explicitly with a scoped policy exemption and an expiry date rather than leaving it silently non-compliant, so the exception is visible and is reviewed before the server outlives its purpose.