WARNING

How to Fix Azure SQL Database Connection Timeout

Quick Fix Summary

TL;DR

Increase the CommandTimeout in your connection string and verify firewall/network rules.

A SqlTimeoutException occurs when a database operation exceeds the allotted time. This is often a network, query performance, or resource constraint issue, not necessarily a database failure.

Diagnosis & Causes

  • Default CommandTimeout (30 seconds) is too low for long-running queries.
  • Network latency or throttling between app and Azure SQL.
  • Database under high load, causing query execution delays.
  • Blocking queries or deadlocks consuming resources.
  • Insufficient DTU/vCore capacity leading to throttled performance.
  • Recovery Steps

    1

    Step 1: Immediate Mitigation - Increase Timeout in Code

    Increase the CommandTimeout in your ADO.NET SqlCommand or connection string to prevent immediate failures while you diagnose.

    csharp
    // In your SqlCommand object
    SqlCommand cmd = new SqlCommand(query, connection);
    cmd.CommandTimeout = 180; // Increase to 180 seconds
    // Or in Connection String
    "Server=tcp:yourserver.database.windows.net;Initial Catalog=YourDB;Persist Security Info=False;User ID=YourUser;Password=YourPassword;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;Command Timeout=180;"
    2

    Step 2: Diagnose with Azure SQL Dynamic Management Views (DMVs)

    Query DMVs to identify long-running or blocked queries causing the timeout.

    sql
    -- Find currently executing long-running queries
    SELECT session_id, command, start_time, status, wait_type, wait_time, last_wait_type, cpu_time, total_elapsed_time, text
    FROM sys.dm_exec_requests CROSS APPLY sys.dm_exec_sql_text(sql_handle)
    WHERE total_elapsed_time > 30000 -- More than 30 seconds
    ORDER BY total_elapsed_time DESC;
    -- Check for blocking chains
    SELECT blocking_session_id, wait_duration_ms, session_id
    FROM sys.dm_os_waiting_tasks
    WHERE blocking_session_id IS NOT NULL;
    3

    Step 3: Scale Database Resources (DTU/vCore)

    Temporarily scale up your Azure SQL tier to rule out resource starvation as the root cause.

    bash
    # Scale using Azure CLI (e.g., to Standard S3)
    az sql db update --resource-group YourResourceGroup --server yourserver --name YourDB --service-objective S3
    # Check current DTU/CPU usage in Azure Portal:
    # Monitor -> Metrics -> 'dtu_consumption_percent' or 'cpu_percent'
    4

    Step 4: Optimize Query Performance & Indexes

    Use Query Performance Insight and Database Advisor in the Azure Portal to identify and fix poorly performing queries.

    sql
    -- Use Query Store to find high-duration queries
    SELECT TOP 10 rs.avg_duration, qt.query_sql_text
    FROM sys.query_store_query_text qt
    JOIN sys.query_store_query q ON qt.query_text_id = q.query_text_id
    JOIN sys.query_store_plan p ON q.query_id = p.query_id
    JOIN sys.query_store_runtime_stats rs ON p.plan_id = rs.plan_id
    WHERE rs.last_execution_time > DATEADD(hour, -1, GETUTCDATE())
    ORDER BY rs.avg_duration DESC;
    5

    Step 5: Configure Connection Pooling Properly

    Ensure connection pooling is configured correctly to avoid the overhead of establishing new connections.

    csharp
    // In .NET connection string, ensure pooling is on (default) and set limits
    string connString = "Server=tcp:yourserver.database.windows.net;...;Pooling=true;Min Pool Size=5;Max Pool Size=100;Connection Lifetime=300;"
    // Important: Always open connections late and close them early in a 'using' block.
    using (SqlConnection connection = new SqlConnection(connString))
    {
        // Your operations here
    }
    6

    Step 6: Implement Resilient Connections with Retry Logic

    Use Polly or built-in SqlClient retry logic to handle transient timeouts gracefully.

    csharp
    // Install-Package Microsoft.Data.SqlClient
    using Microsoft.Data.SqlClient; // Supports built-in retry logic
    SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(YourConnectionString);
    builder.ConnectRetryCount = 3; // Number of retries on connection
    builder.ConnectRetryInterval = 10; // Seconds between retries
    using (SqlConnection connection = new SqlConnection(builder.ConnectionString))
    {
        await connection.OpenAsync(); // Will automatically retry on transient failures
    }

    Architect's Pro Tip

    "For persistent timeouts on complex queries, enable Query Store with 'Forced Plan' for the problematic query as an immediate surgical fix, then optimize the query later."

    Frequently Asked Questions

    What's the difference between Connection Timeout and Command Timeout?

    Connection Timeout is the wait time to establish a network connection to the server (default 15 sec). Command Timeout is the wait time for a specific SQL command to execute (default 30 sec). SqlTimeoutException usually refers to Command Timeout.

    Will increasing CommandTimeout negatively impact my application?

    It can lead to thread pool starvation if many commands hang. Use it as a temporary buffer while fixing the root cause (slow query, blocking, low resources). Always implement async operations and cancellation tokens.

    My timeout happens intermittently. What should I check first?

    Check Azure SQL's 'cpu_percent' and 'dtu_consumption_percent' metrics for spikes coinciding with timeouts. This points to resource throttling, requiring a scale-up or query optimization.

    Related Azure Guides