Is It the Database? Reading ASYNC_NETWORK_IO

A slow application response does not always mean SQL Server is still computing the answer. ASYNC_NETWORK_IO can show that the server has results to send while the receiving side is not consuming them quickly enough.

A combine harvester waiting with its grain arm out while a small red cart slowly returns across the field

Where ASYNC_NETWORK_IO Starts Waiting

The wait occurs when result delivery cannot continue at the required pace. SQL Server and the client exchange data through buffers and the network, and the server can wait for the receiver to make progress. That receiver includes the application's fetch behavior, its machine resources, and the communication path.

Do not translate the wait's name directly into a verdict that the network hardware is faulty. An application that pauses between row fetches can produce the same symptom as a slow transfer path. The database query can also be sending an unnecessarily large result. Investigate the end-to-end flow before assigning ownership of the problem.

I begin by asking whether the application needs all the requested rows and columns. That question can expose excessive output before packet-level investigation is necessary. A query that returns an entire table for a summary screen creates work in the server, connection, client, and display. That cost exists no matter which component becomes the first visible bottleneck.

Find Requests Waiting on ASYNC_NETWORK_IO

Capture the active request, associated session, and relevant text while the symptom is present. The following query limits the output to requests currently showing the wait. A request that had the wait earlier but is now doing something else will not appear, so retain multiple samples or accepted historical evidence.

SELECT r.session_id,r.request_id,r.status,r.wait_type,r.wait_time,
       r.cpu_time,r.total_elapsed_time,r.row_count,
       r.blocking_session_id,s.program_name,s.host_name,
       DB_NAME(r.database_id) AS DatabaseName,t.text AS BatchText
FROM sys.dm_exec_requests AS r
JOIN sys.dm_exec_sessions AS s ON s.session_id=r.session_id
OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) AS t
WHERE r.wait_type=N'ASYNC_NETWORK_IO'
  AND r.session_id<>@@SPID;

Use appropriate performance-state permissions; SQL Server 2022 and later requires VIEW SERVER PERFORMANCE STATE for these instance views. Program and host labels help correlate the connection but are not trusted proof of caller identity. Record the capture time and application request identifier through the approved diagnostic process.

CPU and elapsed time provide context, but their difference is not automatically this one wait's duration. A request changes states throughout execution. Keep current wait_time and cumulative request metrics distinguished in the report. A snapshot is a useful photograph of the request, not its complete biography.

Check Waiting Tasks as Well

A request can involve multiple tasks, and a coordinator's current status does not summarize every task's resource use. Join waiting tasks through the task address to obtain the request identity. That avoids assuming that session ID alone uniquely identifies a request when a session can have multiple active requests.

SELECT w.session_id,t.request_id,w.exec_context_id,
       w.wait_type,w.wait_duration_ms,w.resource_description,
       r.status,r.cpu_time,r.total_elapsed_time
FROM sys.dm_os_waiting_tasks AS w
JOIN sys.dm_os_tasks AS t ON t.task_address=w.waiting_task_address
LEFT JOIN sys.dm_exec_requests AS r
  ON r.session_id=t.session_id AND r.request_id=t.request_id
WHERE w.wait_type=N'ASYNC_NETWORK_IO';

Retain task and request identifiers together when correlating samples. Short waits are normal in a streaming protocol, so focus on sustained or repeated waits that align with the slow user operation. Do not treat the mere presence of a wait type as a defect requiring a configuration change.

Investigate Work Between Row Fetches

A client can fetch one row, perform expensive formatting or calculations, write a file, make another request, and only then ask for the next row. That sequence keeps the result stream open while unrelated application work happens. The server experiences delayed consumption even if its own query processing is efficient.

Ask developers to trace the time spent fetching, processing, and presenting data separately. Where practical, consume bounded batches promptly and process them after the batch is received. Avoid buffering an unlimited result simply to hide the wait; that can exchange a streaming problem for client memory pressure and another failure mode.

Check exception paths and user-interaction pauses too. A reader left open while the application waits for a button click can extend transaction or resource lifetimes. Ensure cancellation and disposal follow the application's supported data-access contract. A screen that looks idle can still own a very active database request.

Where a result slows on its way out: a diagram about the ASYNC_NETWORK_IO

Reduce the Output Behind ASYNC_NETWORK_IO

Filtering and aggregation close to the data can reduce the stream when the application only needs a subset or summary. Select explicit columns and avoid transferring large values that the screen does not use. Make the result contract deliberate, then verify the changed query preserves the required business result.

DECLARE @LastAcceptedOrderID int=500;
SELECT TOP (100) OrderID,CustomerID,OrderDate
FROM dbo.Orders
WHERE OrderID>@LastAcceptedOrderID
ORDER BY OrderID;

This illustrative query assumes an existing Orders table and uses input values to demonstrate bounded key-based retrieval. It does not promise a returned count or constant query cost. A production paging contract needs a stable key and a decision about concurrent changes. Returning less data is useful only when it still fulfills the application's request.

For exports that truly need many rows, design a controlled streaming path rather than pretending the screen's small-page contract applies. Measure transfer volume, consumption pace, and resource limits. ASYNC_NETWORK_IO can be expected during a large export without making every long wait acceptable.

Check the Client Machine and Network Path

Inspect client CPU, memory, storage, and any competing work while the slow fetch occurs. A busy client can delay result consumption despite efficient application code. Correlate timestamps rather than comparing an unrelated quiet machine capture with a busy database interval. The receiving system belongs in the diagnostic evidence.

Then investigate network throughput, latency, retransmissions, and connection interruptions through the approved network process. Compare the same bounded workload from an appropriate controlled location when that test isolates a suspected path. Do not change firewall or encryption settings merely because a wait contains the word network.

A local or nearby fast test is suggestive rather than complete proof. It can also change client resources, driver behavior, and rendering. Keep those differences recorded so the experiment supports the conclusion it is being asked to support.

Explain the Evidence to Developers

I share the request identity, capture interval, selected query shape, and observed waiting pattern with the development team. Then ask for matching fetch-loop and application-stage timings. That gives both sides a specific operation to investigate instead of a discussion about which system is generally faster.

Which step occurs between receiving successive batches? Include that question with the evidence. Suggest bounded retrieval, reduced columns, timely consumption, or separate processing based on what the trace shows. Keep any proposed change reviewable and compare the same user operation after implementation.

Verify the User Operation End to End

Check the resulting application duration as well as server CPU, waits, transferred output, and client resource use. A lower database wait counter is not enough if the application now spends longer buffering or rendering the same result. Successful tuning improves the accepted workflow within its memory and correctness limits.

ASYNC_NETWORK_IO identifies a delivery boundary worth investigating. It does not absolve an excessive database result or prove a network defect. Keep the server query, receiving application, and path in the same evidence chain until the measured bottleneck and verified improvement agree.

Related reading on this blog: Top 3 Wait Stats from Real-World and Get Wait Stats Related to Specific Session ID With sys.dm_exec_session_wait_stats.

Before you blame the network: a checklist on the ASYNC_NETWORK_IO

A delivery wait is not a complete diagnosis, it is evidence that result production and consumption need to be examined together.

Published by Pinal Dave on SQLAuthority. More of my work at pinaldave.com.

Computer Network, SQL DMV, SQL Server, SQL Wait Stats
Previous Post
Reading a Workload Capture Without a Tool
Next Post
SQL SERVER – Performance Tuning – Is It Really A Top Skills for a SQL Server Consultant? – Notes from the Field #059

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.