- Error number
- 8645
- Severity
- 17 (resource or software problem)
- State
- Not documented by Microsoft (not reproduced here)
- Product
- Microsoft SQL Server Database Engine
- Versions
- All supported SQL Server versions (2016 to 2025), Azure SQL Database, Azure SQL Managed Instance
- Category
- Memory
- Last reviewed
- 24 October 2026
On this page
What it means
Error 8645 means a query waited in the queue for a query memory grant (for sorts, hashes and similar operators) for longer than its timeout, because other queries were holding that memory, so SQL Server cancelled it.
Before a query with sort, hash, bulk copy or index build operators starts, it asks for a memory grant. If the memory for grants in its resource pool is already handed out, the query waits on a RESOURCE_SEMAPHORE wait. Microsoft explains that the timeout depends on the estimated query cost (up to 24 hours) and is visible as timeout_sec in sys.dm_exec_query_memory_grants. When it expires, the waiting query gets 8645.
So the failed query is the one that waited, and the cause is the queries that held the memory: one huge grant or many medium ones. The pool name and pool_id in quotes and brackets show where it happened: default (2) for ordinary work, or a Resource Governor pool whose share of memory may be too small. Severity 17 means a resource ran out; the server keeps running. A nearby error is 8651, raised when the grant cannot be made at all.
Common causes
- A few queries with very large memory grants (big sorts and hash joins over many rows) holding most of the grant memory for a long time.
- Many concurrent queries each asking for a medium grant, so the queue builds up during peaks.
- Row estimates far above reality (stale statistics, missing indexes, complex predicates), so grants are much bigger than the memory actually used.
- A Resource Governor pool or workload group limiting grant memory more tightly than its workload needs.
- Too little memory for SQL Server overall, from a low max server memory or other applications on the server.
Diagnose it
Read-only These queries only read metadata and dynamic management views. They do not change data, permissions or configuration, so they are safe to run first.
Are queries waiting for grants, and have grants timed out?
SELECT pool_id, resource_semaphore_id,
target_memory_kb / 1024 AS target_mb, available_memory_kb / 1024 AS available_mb,
granted_memory_kb / 1024 AS granted_mb,
grantee_count, waiter_count, timeout_error_count, forced_grant_count
FROM sys.dm_exec_query_resource_semaphores; waiter_count above 0 with little available memory is the queue that leads to 8645; timeout_error_count counts the timeouts since the instance started.
Who holds the grants, and who is waiting?
SELECT mg.session_id, mg.pool_id, mg.dop,
mg.requested_memory_kb / 1024 AS requested_mb, mg.granted_memory_kb / 1024 AS granted_mb,
mg.max_used_memory_kb / 1024 AS max_used_mb, mg.wait_time_ms, mg.timeout_sec,
t.text AS query_text
FROM sys.dm_exec_query_memory_grants AS mg
OUTER APPLY sys.dm_exec_sql_text(mg.sql_handle) AS t
ORDER BY mg.requested_memory_kb DESC; Rows with granted_mb NULL are waiting. Large grants where max_used_mb is far below granted_mb are oversized because of bad estimates: the queries to tune first.
Which cached queries ask for the largest grants?
SELECT TOP (20) qs.execution_count,
qs.max_grant_kb / 1024 AS max_grant_mb, qs.max_used_grant_kb / 1024 AS max_used_mb,
qs.max_ideal_grant_kb / 1024 AS max_ideal_mb,
SUBSTRING(t.text, 1, 400) AS query_text
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS t
ORDER BY qs.max_grant_kb DESC; The usual culprits, even when the errors are not happening right now. A big gap between max grant and max used points to poor row estimates.
How much has the instance waited for grants, and how are pools set?
SELECT wait_type, waiting_tasks_count, wait_time_ms, max_wait_time_ms
FROM sys.dm_os_wait_stats
WHERE wait_type = N'RESOURCE_SEMAPHORE';
SELECT p.name AS pool_name, p.total_memgrant_count, p.total_memgrant_timeout_count,
p.memgrant_waiter_count, p.max_memory_kb / 1024 AS max_mb, p.used_memory_kb / 1024 AS used_mb
FROM sys.dm_resource_governor_resource_pools AS p;
SELECT g.name AS group_name, g.pool_id, g.request_max_memory_grant_percent,
g.request_memory_grant_timeout_sec, g.queued_request_count
FROM sys.dm_resource_governor_workload_groups AS g; Growing RESOURCE_SEMAPHORE waits, the pool with total_memgrant_timeout_count above 0, and the workload group limits that apply to it (25 percent is the default grant cap; a grant timeout of 0 means the cost-based default).
How to fix it
Each fix is labelled with what it changes. Try read-only checks and the least invasive fix first, and test changes outside production.
Tune the queries with the largest grants
Client or network sideMicrosoft's first steps: find the large consumers and rewrite them to sort and hash less. Add indexes that let them read fewer rows or deliver rows already in order (no sort needed), select only the columns needed, and filter early. This shrinks or removes the grant altogether.
Fix row estimates with current statistics
Changes schemaGrants are sized from estimated rows. Updating statistics on the tables of the oversized queries makes the estimates, and so the grants, realistic. FULLSCAN reads the whole table, so on large tables run it off-peak or use a sample. Keep statistics maintenance scheduled. On recent compatibility levels, memory grant feedback also corrects repeated misestimates automatically.
UPDATE STATISTICS dbo.Orders WITH FULLSCAN;
Cap the grant of a specific query
Client or network sideFor a query whose grant stays far above what it uses, the MAX_GRANT_PERCENT hint limits its grant as a percentage of the available limit (MIN_GRANT_PERCENT guarantees a minimum). Measure the duration afterwards: too small a grant makes sorts and hashes spill to tempdb.
SELECT CustomerId, SUM(Amount) AS Total
FROM dbo.Orders
GROUP BY CustomerId
ORDER BY Total DESC
OPTION (MAX_GRANT_PERCENT = 5);
Review Resource Governor limits for the pool in the message
Changes configurationIf the message names a user-defined pool and its workload genuinely needs more grant memory, review that pool's MAX_MEMORY_PERCENT and the workload group's REQUEST_MAX_MEMORY_GRANT_PERCENT, using the counts from the diagnostics. Equally, Resource Governor can cap a reporting workload so its grants stop starving everything else.
Caution: Resource Governor changes take effect for the whole instance at ALTER RESOURCE GOVERNOR RECONFIGURE and shift memory between workloads. Measure first, change one limit at a time, and record the old values.
Review memory settings, but only after measuring
Changes configurationIf tuning is done and grants still queue, check max server memory, min server memory and min memory per query for unusual values, and whether the server simply needs more RAM. Base any change on measurements of what Windows and SQL Server use.
Caution: sp_configure and RECONFIGURE change the whole instance at once. A higher max server memory with no free RAM starves Windows. Record the old value so you can revert, and apply it in a maintenance window.
Examples
A reporting query times out in the grant queue
Shown as documented by Microsoft; not reproduced here because it needs grant memory to be exhausted on the whole instance. The query that fails waited for others; it is often not the biggest consumer. The level and state a client sees were not observed in the lab, so only the message text is shown; the catalogue severity is 17.
SELECT c.Region, o.ProductId, SUM(o.Amount) AS Total
FROM dbo.Orders AS o
JOIN dbo.Customers AS c ON c.CustomerId = o.CustomerId
GROUP BY c.Region, o.ProductId
ORDER BY Total DESC;
A timeout occurred while waiting for memory resources to execute the query in resource pool 'default' (2). Rerun the query.
How to prevent it
Track RESOURCE_SEMAPHORE waits, Memory Grants Pending and the largest grants in the plan cache or Query Store, so growing grant queues are visible before they time out. Review new reports and batch jobs for big sorts and hashes before they reach production.
Keep statistics current and indexes aligned with the heaviest queries, and run large reporting and maintenance jobs away from peak hours or in a Resource Governor pool sized for them.
Common questions
Should I just rerun the query, as the message says?
Rerunning works when the peak has passed, but the grant queue will build again. Use the diagnostics to find the queries holding the memory.
How long does a query wait before 8645?
Microsoft says the timeout depends on the estimated cost of the query, with a maximum of 24 hours; timeout_sec in sys.dm_exec_query_memory_grants shows it. A Resource Governor workload group can set REQUEST_MEMORY_GRANT_TIMEOUT_SEC.
Does clearing the plan cache help?
Only briefly. Microsoft lists DBCC FREEPROCCACHE as a temporary measure; it does not change the grants the queries need once they compile again.
Learn more on CodeWithSQL
Official documentation
- MSSQLSERVER_8645 (Microsoft Learn)
- Troubleshoot memory grant issues
- sys.dm_exec_query_memory_grants
- Query hints (Transact-SQL)
Last technically reviewed 24 October 2026; examples and diagnostics run on SQL Server 2025 (17.0.1145.4). Message text checked against the engine's sys.messages catalogue.