Execution Timeout Expired. The timeout period elapsed prior to completion of the operation
or the server is not responding. means a command ran longer than its
CommandTimeout, 30 seconds unless you changed it, and Microsoft.Data.SqlClient stopped
waiting. The inner Win32Exception (258): The wait operation timed out is the same
event. Find out why the command is slow, typically a heavy query or a lock held by another
transaction, and raise the timeout only for commands that are legitimately long.
For one command, set command.CommandTimeout; in EF Core, pass
sql => sql.CommandTimeout(60) to UseSqlServer or call
Database.SetCommandTimeout. Connect Timeout in the connection string is
a different timeout and does not help.
The error
PS> .\FixLab.exe 'Server=(localdb)\MSSQLLocalDB;Database=fix6_lab;Integrated Security=true' 'WAITFOR DELAY ''00:00:05''; SELECT ''done''' --timeout 1
ex.Number = -2
Microsoft.Data.SqlClient.SqlException: Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
InnerException: System.ComponentModel.Win32Exception (NativeErrorCode 258): The wait operation timed out.
--- ex.ToString() ---
Microsoft.Data.SqlClient.SqlException (0x80131904): Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
---> System.ComponentModel.Win32Exception (258): The wait operation timed out.
Why it happens
CommandTimeout is how long the client waits for the server to finish a command. The
test asked for a five-second WAITFOR with a one-second limit, and the exception came
after about a second. ex.Number is -2, a client-side code: the server reported no
error, the client simply gave up. When the command was a plain WAITFOR run with
ExecuteNonQuery, or through EF Core's ExecuteSqlRaw, the message carried a
second line, Operation cancelled by user.
The slow part need not be the query at all; it can be a lock. A second session updated a
row inside an open transaction; a read of the same row with a two-second timeout failed with the
same message, and with the default 30 seconds it returned after 9.9 seconds, once the other
transaction ended. While it waited, sys.dm_exec_requests showed who was blocking:
PS> .\FixLab.exe 'Server=(localdb)\MSSQLLocalDB;Database=fix6_lab;Integrated Security=true' 'SELECT session_id, blocking_session_id, wait_type, wait_time, command FROM sys.dm_exec_requests WHERE blocking_session_id <> 0'
69 | 64 | LCK_M_S | 4792 | SELECT
OK (-1 row(s) affected) in 0.0 s
The fix
using var command = new SqlCommand("WAITFOR DELAY '00:00:05'; SELECT 'done'", connection);
command.CommandTimeout = seconds; // the default is 30
Console.WriteLine(command.ExecuteScalar());
PS> .\FixEf.exe slow 10
done
OK in 5.9 s
With ten seconds allowed, the same five-second command finished. In EF Core the setting lives on the provider options, or on the context for one unit of work:
var options = new DbContextOptionsBuilder<ShopContext>()
.UseSqlServer(ConnectionString, sql => sql.CommandTimeout(seconds))
.Options;
db.Database.SetCommandTimeout(TimeSpan.FromSeconds(10));
With CommandTimeout(1) EF Core failed with the same exception; with 10, and with
SetCommandTimeout over an options value of 1, it finished in about 5.5 seconds. In
ASP.NET Core the same lambda goes into AddDbContext. A Command Timeout=10
key in the connection string also worked as the default for every command, while
Connect Timeout=1 changed nothing: it limits only opening the connection (15 seconds by
default).
A larger number is the right fix only for work that is known to be long, such as a report or a bulk job. Otherwise read the query plan, add the missing index, and keep transactions short so they do not hold locks while other requests wait. A value of 0 means wait forever; avoid it.
How it was reproduced
Two console apps from dotnet new console -n FixLab -f net10.0 and
-n FixEf (.NET SDK 10.0.402):
FixLab with Microsoft.Data.SqlClient 7.1.1, whose --timeout option sets
SqlCommand.CommandTimeout, and FixEf with the snippets above and
Microsoft.EntityFrameworkCore.SqlServer 10.0.13. The server was SQL Server 2022 LocalDB
16.0.1210.3 with a test database, fix6_lab. The blocking case used a second session
that ran BEGIN TRAN, an UPDATE and a 15-second WAITFOR before
rolling back.
Frequently asked
- How do I fix Execution Timeout Expired in SqlClient?
- Find why the command is slow first: check the query plan and look for blocking in sys.dm_exec_requests. If the work is legitimately long, raise SqlCommand.CommandTimeout for that command, or use CommandTimeout in UseSqlServer or Database.SetCommandTimeout in EF Core.
- What is the default command timeout in SqlClient and EF Core?
- 30 seconds. SqlCommand.CommandTimeout defaults to 30, and EF Core's SQL Server provider logged CommandTimeout='30' for its commands when nothing was configured.
- Does Connect Timeout fix Execution Timeout Expired?
- No. Connect Timeout limits how long opening the connection may take, 15 seconds by default. A query that runs too long is governed by the command timeout, set on SqlCommand, in EF Core options, or with the Command Timeout connection string key.
Reading a query plan and choosing the index that removes a scan is covered in the indexes part of Database Design for Developers. More decoded errors in the Fixes category.