Securing Azure SQL Database access requires a defense-in-depth approach combining network controls, identity management, and encryption. This guide covers configuring firewall rules, implementing private endpoints, and enabling Microsoft Entra ID authentication for comprehensive database security.
This article is part of our comprehensive guide on Cloud Security Tips for 2026, which covers essential security practices across all major cloud platforms.
Overview
Azure SQL Database security encompasses multiple layers:
- Network security: Firewall rules, private endpoints, and VNet integration
- Identity and access: Microsoft Entra ID authentication and RBAC
- Data protection: Encryption at rest and in transit, data masking
- Auditing and monitoring: Activity logging and threat detection
This guide focuses on the first two layers, which are essential for controlling who can reach your database.
Prerequisites
Before securing Azure SQL Database, ensure you have:
- Azure SQL Database or SQL Server deployed
- Contributor role on the SQL server resource
- Network Contributor role for VNet configuration
- Virtual Network if implementing private endpoints
- Azure CLI or Azure Portal access
Step 1: Configure Firewall Rules
Firewall rules control which IP addresses can connect to your SQL server through the public endpoint.
View and Manage Firewall Rules via Azure Portal
- Navigate to your SQL server (not database) in Azure Portal
- Select Networking under Security
- Under Firewall rules, configure access:
- Allow Azure services: Enable only if Azure services need access
- Add client IP: Add your current IP for management access
- Add firewall rule: Add specific IP ranges
Configure Firewall via Azure CLI
# Set variables
RESOURCE_GROUP="rg-sql-production"
SQL_SERVER="sql-prod-001"
# List existing firewall rules
az sql server firewall-rule list \
--resource-group $RESOURCE_GROUP \
--server $SQL_SERVER \
--output table
# Add a firewall rule for a specific IP
az sql server firewall-rule create \
--resource-group $RESOURCE_GROUP \
--server $SQL_SERVER \
--name "OfficeNetwork" \
--start-ip-address 203.0.113.0 \
--end-ip-address 203.0.113.255
# Add rule for Azure services (use cautiously)
az sql server firewall-rule create \
--resource-group $RESOURCE_GROUP \
--server $SQL_SERVER \
--name "AllowAzureServices" \
--start-ip-address 0.0.0.0 \
--end-ip-address 0.0.0.0
# Delete a firewall rule
az sql server firewall-rule delete \
--resource-group $RESOURCE_GROUP \
--server $SQL_SERVER \
--name "OldRule"
Database-Level Firewall Rules (T-SQL)
-- View database-level firewall rules
SELECT * FROM sys.database_firewall_rules;
-- Add a database-level firewall rule
EXECUTE sp_set_database_firewall_rule
@name = N'DeveloperWorkstation',
@start_ip_address = '192.168.1.100',
@end_ip_address = '192.168.1.100';
-- Delete a database-level firewall rule
EXECUTE sp_delete_database_firewall_rule @name = N'DeveloperWorkstation';
Firewall Best Practices
| Practice | Recommendation |
|---|---|
| Avoid 0.0.0.0/0 | Never allow all IP addresses |
| Use specific ranges | Define narrow IP ranges for offices/VPNs |
| Review regularly | Audit firewall rules quarterly |
| Disable Azure services | Only enable if specifically required |
Step 2: Implement Private Endpoints
Private Endpoints provide the most secure network access by assigning a private IP to Azure SQL within your VNet.
Create Private Endpoint via Azure Portal
- Navigate to your SQL server in Azure Portal
- Select Networking under Security
- Select the Private access tab
- Click + Create a private endpoint
- Configure the endpoint:
- Subscription/Resource group: Select appropriate values
- Name:
pe-sql-prod-001 - Region: Same as your VNet
- Resource tab:
- Target sub-resource:
sqlServer
- Target sub-resource:
- Virtual Network tab:
- Virtual network: Select your VNet
- Subnet: Select a subnet for the endpoint
- Private IP configuration: Dynamic or Static
- DNS tab:
- Integrate with private DNS zone: Yes (recommended)
- Click Create
Create Private Endpoint via Azure CLI
# Set variables
VNET_NAME="vnet-production"
SUBNET_NAME="subnet-data"
PE_NAME="pe-sql-prod-001"
# Get SQL server resource ID
SQL_SERVER_ID=$(az sql server show \
--resource-group $RESOURCE_GROUP \
--name $SQL_SERVER \
--query id -o tsv)
# Get subnet ID
SUBNET_ID=$(az network vnet subnet show \
--resource-group $RESOURCE_GROUP \
--vnet-name $VNET_NAME \
--name $SUBNET_NAME \
--query id -o tsv)
# Create private endpoint
az network private-endpoint create \
--resource-group $RESOURCE_GROUP \
--name $PE_NAME \
--vnet-name $VNET_NAME \
--subnet $SUBNET_NAME \
--private-connection-resource-id $SQL_SERVER_ID \
--group-id sqlServer \
--connection-name "sql-connection"
# Create private DNS zone
az network private-dns zone create \
--resource-group $RESOURCE_GROUP \
--name "privatelink.database.windows.net"
# Link DNS zone to VNet
az network private-dns link vnet create \
--resource-group $RESOURCE_GROUP \
--zone-name "privatelink.database.windows.net" \
--name "sql-dns-link" \
--virtual-network $VNET_NAME \
--registration-enabled false
# Create DNS record
az network private-endpoint dns-zone-group create \
--resource-group $RESOURCE_GROUP \
--endpoint-name $PE_NAME \
--name "sql-dns-group" \
--private-dns-zone "privatelink.database.windows.net" \
--zone-name "privatelink.database.windows.net"
Deny Public Network Access
After configuring Private Endpoints, disable public access:
# Deny public network access
az sql server update \
--resource-group $RESOURCE_GROUP \
--name $SQL_SERVER \
--public-network-access Disabled
# Verify setting
az sql server show \
--resource-group $RESOURCE_GROUP \
--name $SQL_SERVER \
--query publicNetworkAccess
Step 3: Enable Microsoft Entra ID Authentication
Microsoft Entra ID (formerly Azure AD) authentication provides centralized identity management and eliminates the need for SQL passwords.
Set Microsoft Entra Admin via Azure Portal
- Navigate to your SQL server in Azure Portal
- Select Microsoft Entra ID under Settings
- Click Set admin
- Search for and select a user or group
- Click Save
Set Microsoft Entra Admin via Azure CLI
# Set Entra ID admin (user or group)
az sql server ad-admin create \
--resource-group $RESOURCE_GROUP \
--server $SQL_SERVER \
--display-name "SQL Admins" \
--object-id "00000000-0000-0000-0000-000000000000"
# Verify admin configuration
az sql server ad-admin list \
--resource-group $RESOURCE_GROUP \
--server $SQL_SERVER
# Enable Azure AD-only authentication
az sql server ad-only-auth enable \
--resource-group $RESOURCE_GROUP \
--name $SQL_SERVER
Create Database Users for Entra ID Principals
Connect to your database as the Entra ID admin and create contained users:
-- Create user from Entra ID user
CREATE USER [[email protected]] FROM EXTERNAL PROVIDER;
-- Create user from Entra ID group
CREATE USER [SQLReaders] FROM EXTERNAL PROVIDER;
-- Create user from managed identity
CREATE USER [my-app-managed-identity] FROM EXTERNAL PROVIDER;
-- Grant permissions
ALTER ROLE db_datareader ADD MEMBER [SQLReaders];
ALTER ROLE db_datawriter ADD MEMBER [my-app-managed-identity];
Connection String Examples
User with interactive authentication:
Server=sql-prod-001.database.windows.net;Database=mydb;Authentication=Active Directory Interactive
Application with managed identity:
Server=sql-prod-001.database.windows.net;Database=mydb;Authentication=Active Directory Managed Identity
Application with service principal:
Server=sql-prod-001.database.windows.net;Database=mydb;Authentication=Active Directory Service Principal;User Id={client-id};Password={client-secret}
Step 4: Enable Auditing and Threat Detection
Configure auditing to monitor database access:
Enable Server Auditing
# Create storage account for audit logs
AUDIT_STORAGE="stauditlogs$(date +%s)"
az storage account create \
--resource-group $RESOURCE_GROUP \
--name $AUDIT_STORAGE \
--location eastus \
--sku Standard_LRS
# Enable server auditing
az sql server audit-policy update \
--resource-group $RESOURCE_GROUP \
--name $SQL_SERVER \
--state Enabled \
--storage-account $AUDIT_STORAGE \
--retention-days 90
# Enable Advanced Threat Protection
az sql server threat-policy update \
--resource-group $RESOURCE_GROUP \
--name $SQL_SERVER \
--state Enabled \
--email-addresses "[email protected]" \
--email-account-admins Enabled
Audit Log Categories
Configure which operations to audit:
| Category | Description | Recommended |
|---|---|---|
| SUCCESSFUL_DATABASE_AUTHENTICATION | Successful logins | Yes |
| FAILED_DATABASE_AUTHENTICATION | Failed login attempts | Yes |
| BATCH_COMPLETED | All completed queries | For sensitive DBs |
| SCHEMA_OBJECT_ACCESS | Access to tables/views | For compliance |
Security Checklist
Before deploying to production, verify these settings:
- Firewall rules use specific IP ranges, not 0.0.0.0/0
- Private Endpoint configured and DNS resolves correctly
- Public network access disabled (if using Private Endpoints)
- Microsoft Entra ID admin set
- Azure AD-only authentication enabled
- SQL authentication disabled (if possible)
- Auditing enabled with appropriate retention
- Advanced Threat Protection enabled
- TDE (Transparent Data Encryption) enabled (default)
- Minimum TLS version set to 1.2
Troubleshooting
Cannot connect after enabling Private Endpoint:
- Verify DNS resolution returns private IP
- Check NSG rules on the private endpoint subnet
- Ensure client is on a VNet with access to the private endpoint
Entra ID authentication fails:
- Verify user exists in Microsoft Entra ID
- Check user has been created in the database
- Ensure correct authentication method in connection string
Audit logs not appearing:
- Allow 15-30 minutes for initial data
- Verify storage account permissions
- Check audit policy state is Enabled
Next Steps
After securing database access, implement these additional protections:
- Configure Always Encrypted for sensitive columns
- Enable Dynamic Data Masking for PII
- Implement Row-Level Security for multi-tenant databases
- Review Cloud Security Tips for 2026 for comprehensive cloud security guidance