Azure security

How to find SQL servers open to the internet in Azure

Find Azure SQL servers open to the internet with PowerShell and Resource Graph, in the Azure portal's Resource Graph Explorer, or with the Azure SQL Servers report in Altivane across subscriptions.

By the Published Updated

To find SQL servers open to the internet in Azure, check 2 things on each server: whether public network access is on, and whether a firewall rule lets in every address. A rule from 0.0.0.0 to 255.255.255.255 lets in every address, while a rule from 0.0.0.0 to 0.0.0.0 lets in only Azure's own services. Resource Graph can lag a recent change, so confirm a server in the Azure portal before you act.

Choose the method that fits the job
MethodBest fit
PowerShellA repeatable CSV of every SQL server across selected subscriptions, with the firewall rules read for you.
Admin centreA quick look at server settings in Resource Graph Explorer, then the firewall rules of chosen servers.
AltivaneRecommended for recurring reviews across readable subscriptions, with firewall rules and weak points in a workbook.

Before you start

Use an Azure account with read access to the subscriptions you want to check. The built-in Reader role is enough, assigned at the subscription or a parent scope, and no separate licence is needed. The script uses the Az.Accounts, Az.ResourceGraph and Az.Sql modules.

The check covers Azure SQL Database servers, not SQL Managed Instance or SQL Server on a virtual machine. A server is reachable from the internet only when public network access is on and a firewall rule admits the caller's address. Rules set on a single database, which only T-SQL can create, are not read. The examples read and export and change nothing.

Option 1

Find SQL servers open to the internet with PowerShell

Install the modules once and connect to Azure. The script reads each server's settings from Resource Graph, then its firewall rules, and writes 1 row per server with the servers open to every address first.

PowerShell
Install-Module -Name Az.Accounts, Az.ResourceGraph, Az.Sql -Repository PSGallery -Scope CurrentUser
PowerShell
$ErrorActionPreference = 'Stop'
Connect-AzAccount -ErrorAction Stop
try {
    $subscriptionIds = @(
        Get-AzSubscription |
        Where-Object State -eq 'Enabled' |
        Select-Object -ExpandProperty Id
    )
    if ($subscriptionIds.Count -eq 0) {
        Write-Output 'No enabled subscriptions are available to this account.'
        return
    }
    $query = @(
        'Resources'
        '| where type =~ "microsoft.sql/servers"'
        '| project id, name, subscriptionId, resourceGroup,'
        '    serverName = tostring(properties.fullyQualifiedDomainName),'
        '    publicAccess = tostring(properties.publicNetworkAccess),'
        '    minimumTls = tostring(properties.minimalTlsVersion),'
        '    entraOnly = tobool(properties.administrators.azureADOnlyAuthentication),'
        '    entraAdmin = tostring(properties.administrators.login)'
        '| order by publicAccess desc, id asc'
    ) -join ' '
    function Get-AzGraphRows {
        param([string]$Query, [string[]]$SubscriptionIds)
        $results = [System.Collections.Generic.List[object]]::new()
        $skipToken = $null
        do {
            $arguments = @{
                Query = $Query
                Subscription = $SubscriptionIds
                First = 1000
            }
            if ($skipToken) { $arguments.SkipToken = $skipToken }
            $page = Search-AzGraph @arguments
            foreach ($record in $page.Data) { $results.Add($record) }
            $skipToken = $page.SkipToken
        } while ($skipToken)
        return $results.ToArray()
    }
    $servers = @(Get-AzGraphRows -Query $query -SubscriptionIds $subscriptionIds)
    if ($servers.Count -eq 0) {
        Write-Output 'No SQL servers were found in the readable subscriptions.'
        return
    }
    $rows = @(foreach ($server in $servers) {
        $rules = $null
        try {
            Set-AzContext -SubscriptionId $server.subscriptionId | Out-Null
            $ruleArguments = @{
                ResourceGroupName = $server.resourceGroup
                ServerName = $server.name
            }
            $rules = @(Get-AzSqlServerFirewallRule @ruleArguments)
        } catch {
            Write-Warning "Rules not read for $($server.name): $($_.Exception.Message)"
        }
        $ruleCount = 'Not read'
        $everyAddress = 'Not read'
        $azureServices = 'Not read'
        if ($null -ne $rules) {
            $wide = @($rules | Where-Object {
                $_.StartIpAddress -eq '0.0.0.0' -and $_.EndIpAddress -eq '255.255.255.255'
            })
            $azureOnly = @($rules | Where-Object {
                $_.StartIpAddress -eq '0.0.0.0' -and $_.EndIpAddress -eq '0.0.0.0'
            })
            $ruleCount = $rules.Count
            $everyAddress = if ($wide.Count -gt 0) { 'Yes' } else { 'No' }
            $azureServices = if ($azureOnly.Count -gt 0) { 'Yes' } else { 'No' }
        }
        $entraOnly = if ($server.entraOnly) { 'Yes' } else { 'No' }
        $entraAdmin = if ($server.entraAdmin) { $server.entraAdmin } else { 'None' }
        [pscustomobject]@{
            ServerName          = $server.serverName
            SubscriptionId      = $server.subscriptionId
            ResourceGroup       = $server.resourceGroup
            PublicNetworkAccess = $server.publicAccess
            MinimumTls          = $server.minimumTls
            EntraOnlySignIn     = $entraOnly
            EntraAdministrator  = $entraAdmin
            FirewallRules       = $ruleCount
            OpenToEveryAddress  = $everyAddress
            AzureServicesAllowed = $azureServices
        }
    })
    $rows | Sort-Object OpenToEveryAddress -Descending |
        Export-Csv -Path './sql-servers.csv' -NoTypeInformation -Encoding utf8
    $open = @($rows | Where-Object OpenToEveryAddress -eq 'Yes')
    $public = @($rows | Where-Object PublicNetworkAccess -eq 'Enabled')
    Write-Output "$($rows.Count) SQL servers saved to sql-servers.csv."
    Write-Output "$($open.Count) have a firewall rule open to every address."
    Write-Output "$($public.Count) have public network access enabled."
} finally {
    Disconnect-AzAccount | Out-Null
}

The export has each server's address, subscription, resource group, public network access, minimum TLS version, Entra settings, firewall rule count, and whether a rule lets in every address or Azure's services. A server whose rules cannot be read shows Not read and a warning.

To narrow the search, keep only the subscription IDs you want in $subscriptionIds. To keep only servers that can be reached, filter $rows on PublicNetworkAccess before the export. Keep id in the query, because Azure's continuation token needs it.

Option 2

Find open SQL servers in the Azure portal

  1. Sign in to the Azure portal with read access to the subscriptions.
  2. Search for resource graph > choose Resource Graph Explorer.
  3. Paste this query in Query 1 and choose Run query:
    KQL
    Resources
    | where type =~ 'microsoft.sql/servers'
    | project id, name, subscriptionId, resourceGroup,
        serverName = tostring(properties.fullyQualifiedDomainName),
        publicAccess = tostring(properties.publicNetworkAccess),
        minimumTls = tostring(properties.minimalTlsVersion),
        entraOnly = tobool(properties.administrators.azureADOnlyAuthentication),
        entraAdmin = tostring(properties.administrators.login)
    | order by publicAccess desc, id asc
  4. Review the servers in Results. Servers with public network access Enabled come first; only those can be reached from the internet.
  5. To read a server's firewall rules, search for SQL servers, choose the server, then under Security choose Networking and open the Public access tab.
  6. Look for a rule running from 0.0.0.0 to 255.255.255.255, which lets in every address. The Allow Azure services and resources to access this server setting is the rule from 0.0.0.0 to 0.0.0.0.

This suits a one-off check or a few servers, since the rules are opened server by server. For more, use PowerShell.

Common questions

Does Allow Azure services mean a server is open to the internet?

No, but it is wider than most people want. The setting adds a rule from 0.0.0.0 to 0.0.0.0, which lets in every resource inside Azure, whether or not it is in your subscription. The script and report show it separately from a rule open to every address.

Are database-level firewall rules included?

No. Server-level rules, which apply to every database on the server, are the ones read. Database-level rules apply to 1 database and can only be created with T-SQL, so a server with no wide server rule can still admit addresses through them.

What else should I review for internet exposure?

For network security group rules open to the internet, see how to find NSG rules open to the internet in Azure.

Microsoft references

Technical references checked on 8 October 2026. The example scripts have been reviewed and syntax checked; they have not been run against a live tenant.

Talk to us about Altivane

Questions, or pricing? Get in touch.

Contact us