SQL Server connection timeout after idle

Patricia Davidson 20 Reputation points
2024-07-04T17:35:16.3733333+00:00

I just set up on Azure a SQL Server (free tier) connecting to an .NET Core web app also on Azure.

After 20 minutes the database goes idle. The first attempted connection to the database fails with the call stack below. The subsequent call works immediately.

I think it's timing out. But with the connection string set to 60 seconds it is still timing out. Is anyone else having this problem? Did you find a work around or a setting that fixes it? Thank you.

Server=tcp:mcla-server.database.windows.net,1433;Initial Catalog=mcla;Persist Security Info=False;User ID={db_user};Password={your_password};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=60;

Call stack

Database 'mcla' on server 'mcla-server.database.windows.net' is not currently available. Please retry the connection later. If the problem persists, contact customer support, and provide them the session tracing ID of '{D00D6EC1-01AA-4B7B-AF4C-3747604672A8}'.at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction)at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)at Microsoft.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)at Microsoft.Data.SqlClient.SqlInternalConnectionTds.CompleteLogin(Boolean enlistOK)at Microsoft.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean ignoreSniOpenTimeout, TimeoutTimer timeout, Boolean withFailover)at Microsoft.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString connectionOptions, SqlCredential credential, TimeoutTimer timeout)at Microsoft.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectionOptions, SqlCredential credential, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance)at Microsoft.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, Boolean applyTransientFaultHandling, String accessToken, DbConnectionPool pool)at Microsoft.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)at Microsoft.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)at Microsoft.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)at Microsoft.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)at Microsoft.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)at Microsoft.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource1 retry, DbConnectionOptions userOptions)at Microsoft.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource1 retry, DbConnectionOptions userOptions)at Microsoft.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource1 retry, SqlConnectionOverrides overrides)at Microsoft.Data.SqlClient.SqlConnection.Open(SqlConnectionOverrides overrides)at Microsoft.Data.SqlClient.SqlConnection.Open()at AccessJustice.Models.DBAccess..ctor()

ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,611 questions
SQL Server
SQL Server
A family of Microsoft relational database management and analysis systems for e-commerce, line-of-business, and data warehousing solutions.
13,979 questions
0 comments No comments
{count} votes

Accepted answer
  1. Ganeshkumar R 665 Reputation points
    2024-07-04T18:16:08.9866667+00:00

    Implement a keep-alive mechanism in your application to periodically query the database, preventing it from going idle. You can use a background task to accomplish this.

    Example: Keep-Alive Task in ASP.NET Core

    
    public class DatabaseKeepAliveService : IHostedService, IDisposable
    
    {
    
        private Timer _timer;
    
        private readonly string _connectionString;
    
        public DatabaseKeepAliveService(IConfiguration configuration)
    
        {
    
            _connectionString = configuration.GetConnectionString("DefaultConnection");
    
        }
    
        public Task StartAsync(CancellationToken cancellationToken)
    
        {
    
            // Set up a timer to trigger the keep-alive query every 10 minutes
    
            _timer = new Timer(KeepAlive, null, TimeSpan.Zero, TimeSpan.FromMinutes(10));
    
            return Task.CompletedTask;
    
        }
    
        private void KeepAlive(object state)
    
        {
    
            using (var connection = new SqlConnection(_connectionString))
    
            {
    
                try
    
                {
    
                    connection.Open();
    
                    using (var command = new SqlCommand("SELECT 1", connection))
    
                    {
    
                        command.ExecuteScalar();
    
                    }
    
                }
    
                catch (Exception ex)
    
                {
    
                    // Handle exceptions as needed
    
                }
    
            }
    
        }
    
        public Task StopAsync(CancellationToken cancellationToken)
    
        {
    
            _timer?.Change(Timeout.Infinite, 0);
    
            return Task.CompletedTask;
    
        }
    
        public void Dispose()
    
        {
    
            _timer?.Dispose();
    
        }
    
    }
    
    

    Register the Service

    In your Startup.cs or Program.cs, register the DatabaseKeepAliveService:

    
    public void ConfigureServices(IServiceCollection services)
    
    {
    
        services.AddHostedService<DatabaseKeepAliveService>();
    
        // Other services
    
    }
    
    

    Although you mentioned setting the connection timeout to 60 seconds, ensure that it's correctly set in the connection string. However, this alone might not resolve the issue if the database takes longer to wake up.

    Consider upgrading to a higher pricing tier that does not have aggressive idle timeout settings. The free tier and lower pricing tiers may have limitations that cause the database to go idle more frequently.

    Implement retry logic in your application to handle transient failures. This can help mitigate the impact of the initial connection failure when the database is waking up.

    Example: Retry Logic with Polly

    
    public class DatabaseService
    
    {
    
        private readonly string _connectionString;
    
        public DatabaseService(IConfiguration configuration)
    
        {
    
            _connectionString = configuration.GetConnectionString("DefaultConnection");
    
        }
    
        public async Task ExecuteQueryAsync()
    
        {
    
            var policy = Policy
    
                .Handle<SqlException>()
    
                .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
    
            await policy.ExecuteAsync(async () =>
    
            {
    
                using (var connection = new SqlConnection(_connectionString))
    
                {
    
                    await connection.OpenAsync();
    
                    using (var command = new SqlCommand("YOUR SQL QUERY", connection))
    
                    {
    
                        await command.ExecuteNonQueryAsync();
    
                    }
    
                }
    
            });
    
        }
    
    }
    
    

    By implementing these strategies, you can mitigate the issue of the database going idle and improve the reliability of your application's database connections.

    1 person found this answer helpful.

2 additional answers

Sort by: Most helpful
  1. Bruce (SqlWork.com) 66,621 Reputation points
    2024-07-04T18:22:38.71+00:00

    The first connection to an idle azure sql database can take over a minute ( the server needs to be spun up). As suggested you can do a keep alive (but then your website must not idle down).


  2. Erland Sommarskog 112.7K Reputation points MVP
    2024-07-04T20:25:56.0333333+00:00

    Apparently, you have a Serverless database.

    Advantage with Serverless: when you don't use it, it can be unloaded, and you save a lot of money.

    Disadvantage with Serverless: First connection can take some time.

    In your case, you have a free tier, so there is no cost involved. But I suspect that you run out of credits if you implement any form of keepalive as suggested in the other post.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.