Dapper.NET
CommandTimeout
database optimization
C# programming
.NET development

Adjusting CommandTimeout in Dapper.NET?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Dapper, CommandTimeout controls how long a SQL command is allowed to execute before the database provider aborts it. The setting is easy to change, but it is worth understanding exactly what it covers so you do not mask slow-query problems with a larger timeout value.

Core Sections

What CommandTimeout means in Dapper

Dapper is a thin layer on top of ADO.NET, so timeout behavior ultimately comes from the provider’s DbCommand.CommandTimeout. This is the execution timeout for a single SQL command. It is not the same thing as the connection timeout used when opening a connection.

That distinction matters because people often increase the connection timeout while the actual failure is happening after the connection is already open.

A command timeout applies to operations such as:

  • 'SELECT statements'
  • 'INSERT, UPDATE, and DELETE'
  • stored procedure execution
  • async query calls

If the configured time budget is exceeded, the provider typically throws an exception such as SqlException.

Set the timeout per query when only one call is slow

The most precise approach is to pass commandTimeout directly on the Dapper call that needs a longer budget.

csharp
1using System;
2using System.Data;
3using System.Data.SqlClient;
4using Dapper;
5
6using var connection = new SqlConnection(connectionString);
7
8var orders = connection.Query<Order>(
9    "SELECT * FROM Orders WHERE CreatedAt >= @Since",
10    new { Since = DateTime.UtcNow.AddDays(-30) },
11    commandTimeout: 120
12).AsList();

This keeps the override next to the actual query and avoids surprising the rest of the codebase. It is usually the best default when only a few reporting or maintenance queries run longer than normal.

The same pattern works for non-query commands.

csharp
1var rows = connection.Execute(
2    "EXEC dbo.RebuildReportingSnapshot",
3    commandType: CommandType.StoredProcedure,
4    commandTimeout: 300
5);

Async calls still honor the same timeout

Switching to QueryAsync or ExecuteAsync does not remove the need to think about SQL execution time. The database still needs time to finish the work, and the provider still enforces the timeout.

csharp
1using var connection = new SqlConnection(connectionString);
2
3var customers = await connection.QueryAsync<Customer>(
4    "SELECT * FROM Customers WHERE IsActive = 1",
5    commandTimeout: 60
6);

async changes how your application thread waits, not how expensive the query is.

Use a global default only when it reflects application-wide policy

Dapper also exposes a global default through SqlMapper.Settings.CommandTimeout.

csharp
Dapper.SqlMapper.Settings.CommandTimeout = 90;

This can be useful in services where most commands genuinely need a non-default timeout. Even then, use it carefully. A large global timeout can quietly make slow paths seem acceptable when they should be investigated and optimized.

A reasonable pattern is:

  • keep the global default modest
  • use per-call overrides for known long-running operations
  • document why a specific command needs extra time

CommandDefinition gives more explicit control

If a call also needs a cancellation token, transaction, or command type, CommandDefinition is often cleaner than a long parameter list.

csharp
1var command = new CommandDefinition(
2    commandText: "SELECT * FROM Logs WHERE Level = @Level",
3    parameters: new { Level = "Error" },
4    commandTimeout: 45,
5    cancellationToken: cancellationToken
6);
7
8var logs = await connection.QueryAsync<LogEntry>(command);

This is a good option when command execution policy is part of a broader unit of work.

Raise the timeout only after checking the query itself

A longer timeout is sometimes correct, especially for data migrations, snapshot jobs, or reports that intentionally scan a lot of data. But in request-path code, repeated timeout failures usually point to a deeper issue:

  • missing indexes
  • blocking or deadlocks
  • bad execution plans
  • parameter-sensitive queries
  • too much data being returned

Changing the timeout should follow investigation, not replace it. If a query suddenly needs five times longer than before, the interesting problem is rarely the timeout value.

Common Pitfalls

  • Confusing connection timeout with command timeout leads to changing the wrong setting and seeing no improvement.
  • Setting a very large global timeout can hide performance regressions that should be fixed in SQL or schema design.
  • Assuming async Dapper calls make slow queries harmless ignores the fact that the database still does the same work.
  • Raising the timeout for user-facing request paths without checking indexes or blocking usually treats the symptom instead of the cause.
  • Forgetting to document why one query has an unusually high timeout makes future maintenance harder.

Summary

  • 'CommandTimeout controls how long a database command may execute before the provider aborts it.'
  • The clearest solution is usually a per-call commandTimeout on the specific Dapper query or command.
  • Async Dapper operations still use the same command-timeout model.
  • Global timeout changes should be deliberate because they affect the whole application.
  • Increase the timeout only after deciding that the query is legitimately long-running rather than simply inefficient.

Course illustration
Course illustration

All Rights Reserved.