Idle SQL Server Instances Still Accumulate Undocumented Wait Types

You open a wait statistics report from a quiet SQL Server instance and an unfamiliar wait type is already there. Nobody ran the workload you care about. The wait count is small. The name is not on the Microsoft Learn wait-type table. The report now has a row that can take attention from the workload you are trying to measure.

A woman DBA with a mug of tea watches a row of hourglasses in a quiet server room, where a few hourglasses keep trickling sand.

This post is part of the Undocumented Changes in SQL Server 2022 and 2025 series. The contents page lists every part in order.

This is a follow-up to the SQL Server 2022 wait-type post. It also follows the SQL Server 2025 columnstore transcoder wait-type post. In those posts, I counted wait types that Microsoft describes, wait types that Microsoft lists as “Internal use only”, and wait types I could not find on the Learn page at all. For this post, I asked two practical questions. Which undocumented names accumulate when the instance is idle? How can a report keep them out of top waits while still showing that they were suppressed?

sys.dm_os_wait_stats is the dynamic management view (DMV) that returns completed wait statistics. Microsoft says the counters are cumulative since the last database engine restart or the last manual reset. The same page points to sys.dm_os_sys_info.sqlserver_start_time for the startup time.[1] I did not clear the counters. I sampled them twice, about ten minutes apart, on an idle SQL Server 2019 instance and an idle SQL Server 2025 instance.

The read-only capture

This is the shape of the query I ran on each instance. It reads only two DMVs and does not reset wait statistics.

The two samples were 604 seconds apart. The 2019 instance had started at 2026-09-26 15:38:56 local time. The 2025 instance had started at 2026-09-26 15:41:37 local time. I kept every wait type with a non-zero total in the second sample or a non-zero delta between samples.

Then I classified each row from the local learn-waits-classified.tsv file. The statuses are described, listed-internal-only, listed-not-supported, and not-listed. For each non-described wait type, I also searched three documentation source repositories. The search used a whole-word, fixed-string git grep. If the case-sensitive search found nothing, I repeated it case-insensitively.[2]

The not-listed idle waits

I found twelve not-listed wait types with a non-zero total or a non-zero delta across the two idle instances. None had an exact-name hit in the three documentation repositories.

Wait type Instance where I saw it Count in second sample Count delta Wait time delta ms
AZURE_IMDS_VERSIONS 2025 1 0 0
DTC_INFO_DMV 2025 1 0 0
POPULATE_LOCK_ORDINALS 2025 1 0 0
PREEMPTIVE_SERVICE_CONTROL_MANGER 2025 4 4 84
PREEMPTIVE_SNI_SOCKET_BIND 2025 4 0 0
PREEMPTIVE_SNI_SOCKET_LISTEN 2025 4 0 0
PVS_PREALLOCATE 2019 and 2025 1 and 8 0 and 7 0 and 16667523
SLEEP_BPOOL_STEAL 2019 31 7 109
SLEEP_PHYSMASTERDBREADY 2025 1 0 0
SOS_WORKER_MIGRATION 2019 52 0 0
XE_SQL_TEXT_HEAP_ALLOC 2025 4 4 5
XE_SQL_TEXT_HEAP_FREE 2025 4 4 0

The earlier 2025 finding was still present. PREEMPTIVE_SNI_SOCKET_BIND, PREEMPTIVE_SNI_SOCKET_LISTEN, DTC_INFO_DMV, AZURE_IMDS_VERSIONS, and POPULATE_LOCK_ORDINALS still had non-zero counts on the idle 2025 instance. They did not move during this ten-minute sample. They were already present before the sample window and did not move during it.

PVS_PREALLOCATE was present on both instances. On the 2025 instance, it gained 7 waits and about 16.7 million milliseconds of accumulated wait time during the sample. Accumulated wait time is not elapsed wall-clock time, and I am not treating that row as a performance problem on an idle test instance. I am treating it as a good example of why a wait report needs a documentation status and an idle-baseline bucket. If a percentage report includes that idle-baseline row in the denominator, the top-waits list can point at background activity instead of user workload.

Internal-only idle waits are a separate bucket

If I treat “Internal use only” as undocumented, there were many more idle rows. The 2019 sample had 42 non-described wait types with a non-zero delta. The 2025 sample had 56. Most were internal-only PREEMPTIVE_OS_*, Extended Events, Query Store, tracing, or background sleep names.

That does not mean all internal-only waits are background activity. It means the Microsoft table does not give a troubleshooting description for them. For reporting, I separate three ideas that often get mixed together:

  • Described by Microsoft.
  • Listed by Microsoft, but with no public description.
  • Not listed by Microsoft and not found in the documentation source search.

That split stops the report from mixing three different facts. A wait type can be benign on an idle box. It can still be worth investigating on a production instance if the count or time changes with the workload.

Community exclusion lists help, but they lag new names

Paul Randal’s SQLskills wait statistics script filters a list of waits that are “almost 100% never a problem” so they do not skew the results.[3] Brent Ozar Unlimited’s sp_BlitzFirst also keeps a wait category table and marks some waits as ignorable.[4]

For the twelve not-listed idle waits above, those lists covered only two names in my comparison:

Wait type SQLskills filtered sp_BlitzFirst ignorable
PVS_PREALLOCATE yes no
POPULATE_LOCK_ORDINALS no yes
All other not-listed idle waits above no no

Exclusion lists are maintenance work, and each script has its own goal. They have to be conservative, because an over-broad exclusion removes a row from the main report. A new or undocumented wait type must not disappear from your report only because it looks like an idle wait on my laptop.

A query that keeps the status visible

This query uses a small VALUES list from this test. In a real reporting job, I keep this list in a table with the source, capture date, SQL Server version, and a review note. The main part is the report_bucket column. A reporting query can use it to move idle-baseline rows out of the main top-waits section while a companion section still shows those rows.

For a production report, I do not delete idle-baseline rows. I remove them from the denominator for the top-waits percentage. Then I print them in a lower section named something like “suppressed idle-baseline waits”. That reporting choice can make the first page easier to read. It also leaves a record if one of those wait types starts moving after a patch or workload change.

What I do not do

I do not copy every community exclusion list into a report without looking at the SQL Server version and capture window. The exclusion lists I checked did not include most of the SQL Server 2025 names that Learn does not list. I also do not add a broad pattern such as PREEMPTIVE_% or SLEEP_%. The idle sample had benign-looking names in those families, but that does not make the whole family safe to suppress.

Most of all, I do not call this a production baseline. These were two local idle test instances, and one idle test instance is not evidence for your estate. The method is the part I reuse. Sample without clearing. Compute the delta. Label the documentation status. Compare against known exclusion lists. Move exact-name idle-baseline rows out of the main top-waits section only when you still show those rows somewhere else.

Have you seen one of these wait types with a real workload, or do you know of documentation my searches missed? Tell me on Bluesky or LinkedIn, and I’ll update the notes.

References

  1. sys.dm_os_wait_stats (Transact-SQL) - Microsoft Learn. Source for the DMV definition, cumulative counter behaviour, reset note, and sqlserver_start_time guidance. ↩
  2. MicrosoftDocs/sql-docs, MicrosoftDocs/azure-docs and MicrosoftDocs/fabric-docs - GitHub. The Markdown source repositories searched with whole-word, fixed-string git grep on 2026-09-26. ↩
  3. SQL Server Wait Statistics, or please tell me where it hurts - SQLskills. Source for Paul Randal’s wait statistics script and its benign-wait exclusion list as fetched on 2026-09-26. ↩
  4. sp_BlitzFirst.sql - Brent Ozar Unlimited, SQL Server First Responder Kit. Source for the wait category table and ignorable-wait flags as fetched on 2026-09-26. ↩