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.