Introduction
Azure SQL Database uses Database Transaction Units (DTUs) to measure resource consumption (CPU, memory, I/O). When DTU usage exceeds the tier limit, queries are throttled, connections may fail, and performance degrades significantly.
Symptoms
DTU throttling error:
Error: 10936, Resource governor limit reached
The resource limit for the database has been reached. Please try again later.Connection refused:
{
"error": {
"code": "ResourceLimitExceeded",
"message": "The request limit for the database is exceeded. Maximum concurrent requests: 100."
}
}Slow query performance:
```bash $ az sql db show \ --name my-database \ --server my-server \ --resource-group my-rg \ --query '{ServiceTier:sku.name,DTUCapacity:sku.capacity}'
# Query returns tier limits, but monitoring shows exceeding ```
Common Causes
- 1.Tier too low - Basic/Standard tier insufficient for workload
- 2.Query inefficiency - Poorly optimized queries consume excessive DTUs
- 3.High concurrency - Too many simultaneous connections/queries
- 4.Batch operations - Large data imports/exports spike DTU usage
- 5.Missing indexes - Full table scans consume high CPU and I/O
- 6.Connection leaks - Open connections not properly closed
- 7.Scheduled jobs - Concurrent scheduled tasks exceed limits
Step-by-Step Fix
Step 1: Check DTU Usage
```bash # Check current DTU usage az monitor metrics list \ --resource /subscriptions/SUB/resourceGroups/my-rg/providers/Microsoft.Sql/servers/my-server/databases/my-database \ --metric "dtu_usage" \ --query 'value[].timeseries[].data[].average'
# Check DTU limit az sql db show \ --name my-database \ --server my-server \ --resource-group my-rg \ --query '{Name:name,Sku:sku,MaxDTU:sku.capacity}' ```
Step 2: Analyze Resource Consumption
```sql -- Query DTU breakdown via sys.dm_db_resource_stats sqlcmd -S my-server.database.windows.net -d my-database -U admin -P password -Q " SELECT AVG(avg_cpu_percent) as avg_cpu, AVG(avg_data_io_percent) as avg_io, AVG(avg_log_write_percent) as avg_log, AVG(avg_memory_usage_percent) as avg_memory, MAX(avg_cpu_percent) as max_cpu, MAX(avg_data_io_percent) as max_io FROM sys.dm_db_resource_stats WHERE end_time > DATEADD(hour, -1, GETDATE()) "
-- If avg_cpu > 80%, CPU is bottleneck -- If avg_io > 80%, I/O is bottleneck ```
Step 3: Upgrade Service Tier
```bash # Check available tiers az sql db list-editions \ --location eastus \ --query "[?contains(name, 'Standard') || contains(name, 'Premium')].{Name:name,Capacity:capacity,Unit:unit}"
# Upgrade to higher tier az sql db update \ --name my-database \ --server my-server \ --resource-group my-rg \ --sku Standard \ --capacity 200 # S3 tier (200 DTU)
# Or upgrade to Premium for vCore model az sql db update \ --name my-database \ --server my-server \ --resource-group my-rg \ --sku Premium \ --capacity 4 \ --family Gen5
# Or use elastic pool for shared DTU az sql elastic-pool create \ --name my-pool \ --server my-server \ --resource-group my-rg \ --sku Standard \ --capacity 400 # Shared among multiple databases ```
Step 4: Identify High DTU Queries
```sql -- Find queries consuming high CPU sqlcmd -S my-server.database.windows.net -d my-database -U admin -P password -Q " SELECT TOP 10 qs.query_hash, qs.execution_count, qs.total_elapsed_time / qs.execution_count as avg_elapsed_time_ms, qs.total_worker_time / qs.execution_count as avg_cpu_time_ms, qs.total_logical_reads / qs.execution_count as avg_reads, SUBSTRING(st.text, (qs.statement_start_offset/2)+1, ((CASE qs.statement_end_offset WHEN -1 THEN DATALENGTH(st.text) ELSE qs.statement_end_offset END - qs.statement_start_offset)/2) + 1) as query_text FROM sys.dm_exec_query_stats qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st ORDER BY qs.total_worker_time DESC "
-- Queries with high avg_cpu_time_ms are DTU-heavy ```
Step 5: Optimize High DTU Queries
```sql -- Check execution plans for expensive queries sqlcmd -S my-server.database.windows.net -d my-database -U admin -P password -Q " SELECT qp.query_plan, st.text FROM sys.dm_exec_query_stats qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp WHERE qs.total_worker_time > 10000000 "
-- Common optimizations: -- 1. Add missing indexes CREATE INDEX IX_Orders_CustomerId ON Orders(CustomerId);
-- 2. Reduce query scope SELECT TOP 100 * FROM LargeTable WHERE Date > '2024-01-01';
-- 3. Use query hints SELECT * FROM Orders WITH (NOLOCK) WHERE CustomerId = 1;
-- 4. Batch operations instead of single-row INSERT INTO Target (Col1, Col2) SELECT Col1, Col2 FROM Source WHERE Processed = 0; ```
Step 6: Check for Missing Indexes
```sql -- Query missing index recommendations sqlcmd -S my-server.database.windows.net -d my-database -U admin -P password -Q " SELECT mid.statement as table_name, mid.equality_columns, mid.inequality_columns, mid.included_columns, migs.avg_user_impact, migs.user_seeks, migs.user_scans FROM sys.dm_db_missing_index_details mid JOIN sys.dm_db_missing_index_groups mig ON mid.index_handle = mig.index_handle JOIN sys.dm_db_missing_index_group_stats migs ON mig.index_group_handle = migs.group_handle ORDER BY migs.avg_user_impact DESC "
-- Create high-impact missing indexes CREATE INDEX IX_Missing_Index ON TableName(Column1, Column2) INCLUDE (Column3); ```
Step 7: Implement Connection Pooling
```bash # Application connection pooling configuration # .NET example: ConnectionString = "Server=my-server.database.windows.net;Database=my-database;User Id=admin;Password=***;Pooling=true;Min Pool Size=5;Max Pool Size=100;Connection Timeout=30;"
# Java example: ConnectionPoolDataSource ds = new ConnectionPoolDataSource(); ds.setUrl("jdbc:sqlserver://my-server.database.windows.net;database=my-database"); ds.setMinPoolSize(5); ds.setMaxPoolSize(100);
# Benefits: # - Reuses connections instead of creating new # - Reduces connection overhead DTU consumption # - Limits concurrent connections ```
Step 8: Schedule Heavy Operations
```bash # Schedule batch operations during low usage # Via Azure Automation or scheduled jobs
# Check usage pattern az monitor metrics list \ --resource /subscriptions/SUB/resourceGroups/my-rg/providers/Microsoft.Sql/servers/my-server/databases/my-database \ --metric "dtu_usage" \ --start-time "2024-01-15T00:00:00Z" \ --end-time "2024-01-15T23:59:59Z" \ --interval PT1H
# Schedule heavy queries during off-peak hours (e.g., 2-6 AM) ```
Step 9: Use Elastic Pool
```bash # For multiple databases with variable usage az sql elastic-pool show \ --name my-pool \ --server my-server \ --resource-group my-rg \ --query '{Name:name,DTU:sku.capacity,DatabaseCount:databaseCount}'
# Add database to pool az sql db update \ --name my-database \ --server my-server \ --resource-group my-rg \ --elastic-pool my-pool
# Set per-database limits in pool az sql db update \ --name my-database \ --server my-server \ --resource-group my-rg \ --elastic-pool my-pool \ --max-capacity 50 # Max DTU for this database ```
Step 10: Monitor and Alert
```bash # Create alert for DTU threshold az monitor metrics alert create \ --name sql-dtu-alert \ --resource-group my-rg \ --scopes /subscriptions/SUB/resourceGroups/my-rg/providers/Microsoft.Sql/servers/my-server/databases/my-database \ --condition "avg dtu_usage > 80" \ --window-size 5m \ --evaluation-frequency 1m
DTU Tier Limits
| Tier | DTU Range | Max Storage | Best For |
|---|---|---|---|
| Basic | 5 | 2 GB | Development |
| Standard S0-S3 | 10-100 | 250 GB | Light workloads |
| Standard S4-S12 | 200-3000 | 500 GB-4 TB | Medium workloads |
| Premium P1-P15 | 125-4000 | 500 GB-4 TB | Critical workloads |
Verification
```bash # After upgrading tier or optimizing az sql db show \ --name my-database \ --server my-server \ --resource-group my-rg \ --query '{Sku:sku.name,Capacity:sku.capacity}'
# Monitor DTU usage for 24 hours az monitor metrics list \ --resource /subscriptions/SUB/resourceGroups/my-rg/providers/Microsoft.Sql/servers/my-server/databases/my-database \ --metric "dtu_usage" \ --query 'value[].timeseries[].data[].average'
# Should show average < 80% of new capacity ```
Prevention
To prevent Azure SQL DTU limit issues from recurring, implement these proactive measures:
1. Monitor DTU Usage
groups:
- name: azure-sql-dtu
rules:
- alert: AzureSQLDTUHighUsage
expr: |
azure_sql_dtu_usage_percent > 85
for: 10m
labels:
severity: warning
annotations:
summary: "Azure SQL database DTU usage exceeds 85%"2. Set Up Auto-Scale
```bash # Configure autoscale for Azure SQL az monitor autoscale create \ --resource /subscriptions/SUB/resourceGroups/my-rg/providers/Microsoft.Sql/servers/my-server/databases/my-database \ --name sql-autoscale \ --min-capacity 10 \ --max-capacity 100 \ --count 50
# Add scale-out rule az monitor autoscale rule create \ --resource-group my-rg \ --autoscale-name sql-autoscale \ --scale out 10 \ --condition "dtu_usage > 80 count 5m" ```
3. Optimize Queries Regularly
```sql -- Weekly query performance review SELECT TOP 10 query_text, execution_count, total_elapsed_time / execution_count as avg_time FROM sys.dm_exec_query_stats CROSS APPLY sys.dm_exec_sql_text(sql_handle) ORDER BY avg_time DESC;
-- Identify missing indexes SELECT * FROM sys.dm_db_missing_index_details; ```
Best Practices Checklist
- [ ] Monitor DTU usage with alerts
- [ ] Set up auto-scale
- [ ] Optimize queries regularly
- [ ] Review index usage
- [ ] Scale before peak usage
- [ ] Use elastic pools for multiple databases
Related Issues
- [Fix Azure SQL Database Deadlock](/articles/fix-azure-sql-database-deadlock)
- [Fix Azure SQL Transaction Log Full](/articles/fix-azure-sql-transaction-log-full)
- [Fix Azure SQL Query Timeout](/articles/fix-azure-sql-database-dtu-limit)
Related Articles
- [Technical troubleshooting: Fix Azure Aks Pod Crashloopbackoff Issue in Azure](azure-aks-pod-crashloopbackoff)
- [Technical troubleshooting: Fix Azure Api Management Policy Expression Runtime](azure-api-management-policy-expression-runtime-error)
- [Technical troubleshooting: Fix Azure App Configuration Feature Flag Not Refre](azure-app-configuration-feature-flag-not-refreshing)
- [Technical troubleshooting: Fix Azure App Service 503 Always On Disabled Issue](azure-app-service-503-always-on-disabled)
- [Technical troubleshooting: Fix Azure Application Gateway Err SSL Unrecognized](azure-application-gateway-err-ssl-unrecognized-name-alert)
<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "TechArticle", "headline": "Fix Azure SQL Database DTU Limit", "description": "Troubleshoot Azure SQL DTU throttling. Upgrade service tier, optimize queries, and implement connection pooling.", "url": "https://www.fixwikihub.com/fix-azure-sql-database-dtu-limit", "publisher": { "@type": "Organization", "name": "FixWikiHub", "url": "https://www.fixwikihub.com" }, "author": { "@type": "Person", "name": "FixWikiHub Editorial Team" }, "datePublished": "2026-04-03T15:47:12.852Z", "dateModified": "2026-04-03T15:47:12.852Z" } </script>