What it is
An Azure Database for MySQL flexible server with network.publicNetworkAccess set to Enabled. The server carries a publicly resolvable hostname and accepts connection attempts on port 3306 from any address a firewall rule permits. Those rules are bare IP allow-lists: they check where a packet claims to come from, never who sent it.
Why it happens
MySQL flexible server locks in its connectivity method at creation, and a server created with public access cannot be converted to private VNet integration afterward. The portal's quickstart path steers toward public access because it works immediately from anywhere, which is exactly what a team wants during a migration or proof of concept. By the time the workload is production, the immutability rule has turned "switch to private" into what looks like a restore-and-cutover project, so the public endpoint stays.
The rules guarding it then accumulate the usual sediment: a developer's home IP from two jobs ago, a broad office range, and often the "allow public access from Azure services" checkbox, which admits connections from any Azure subscription, including other customers'.
What it costs / blast radius
Port 3306 is one of the most scanned ports on the internet, and a public endpoint means every credential leak, weak password, or overbroad firewall rule is exploitable from anywhere on earth rather than from inside your network. There is no MFA and no identity at the network layer; a matching source IP plus a valid login is the entire story, and the prize is every schema on the server.
The way out does not require the dreaded rebuild: a public-access server supports Private Link, so you can attach a private endpoint and disable the public endpoint in place. (Authored assessment of Azure behavior; exposure depends on your firewall rules and credentials.)
See it
resource mysql 'Microsoft.DBforMySQL/flexibleServers@2023-12-30' = {
name: 'app-mysql'
location: location
sku: { name: 'Standard_D2ads_v5', tier: 'GeneralPurpose' }
properties: {
version: '8.0.21'
network: {
publicNetworkAccess: 'Enabled' // internet-facing on port 3306
}
// ...firewall rules decide who gets to try a login
}
}resource mysql 'Microsoft.DBforMySQL/flexibleServers@2023-12-30' = {
name: 'app-mysql'
location: location
sku: { name: 'Standard_D2ads_v5', tier: 'GeneralPurpose' }
properties: {
version: '8.0.21'
network: {
publicNetworkAccess: 'Disabled'
}
}
}
resource mysqlPe 'Microsoft.Network/privateEndpoints@2023-09-01' = {
name: 'app-mysql-pe'
location: location
properties: {
subnet: { id: appSubnetId }
privateLinkServiceConnections: [
{
name: 'app-mysql-plsc'
properties: {
privateLinkServiceId: mysql.id
groupIds: ['mysqlServer']
}
}
]
}
}How StratoLens helps
StratoLens automatically flags every MySQL flexible server that still exposes a public endpoint, continuously and across every subscription in your tenant, so the proof-of-concept server that graduated to production can't hide behind a networking decision made on day one. It all runs inside your own tenant.