An upgrade adds unfamiliar parallel waits near the top of your report. CXSYNC_PORT describes exchange synchronization work, and its presence alone does not establish that parallelism needs to be reduced.

Identify CXSYNC_PORT Before Treating It
SQL Server 2022 introduced CXSYNC_PORT and CXSYNC_CONSUMER for exchange synchronization. Their names distinguish work that previously sat inside broader parallel-wait categories. A changed category after an upgrade can therefore change your report without creating a new workload problem.
CXSYNC_PORT occurs while opening, closing, and synchronizing exchange ports between producers and consumers. CXSYNC_CONSUMER occurs when consumers wait to reach an exchange synchronization point. Both describe coordination inside parallel execution.
I read these waits beside the actual plan, not as a verdict on the server's MAXDOP setting. A parallel query has work that finishes at different times. Synchronization exists because its threads need to exchange and complete that work correctly.
A long sort can delay synchronization at an exchange. Uneven row distribution can also leave one worker busy while others wait. Investigate that operator or distribution rather than prescribing a server-wide setting from a wait name.
Use the documented wait descriptions for the installed version. The examples target SQL Server 2022 or later. Older instances will not show these categories simply because a monitoring query asks for them.
Separate Server Totals From One Session
sys.dm_os_wait_stats contains accumulated waits for the instance. Those totals combine many requests and periods. They are useful for context, but they do not identify which query generated a particular wait.
SELECT wait_type, waiting_tasks_count, wait_time_ms,
signal_wait_time_ms
FROM sys.dm_os_wait_stats
WHERE wait_type LIKE N'CX%'
ORDER BY wait_time_ms DESC;
SELECT session_id, wait_type, waiting_tasks_count, wait_time_ms
FROM sys.dm_exec_session_wait_stats
WHERE session_id = @@SPID AND wait_type LIKE N'CX%'
ORDER BY wait_time_ms DESC;Session statistics narrow the scope to the connection you are testing. They still accumulate work over the session's lifetime. A query window used for several tests needs a before snapshot for each comparison.
The wait_time_ms total is summed across waiting tasks. Parallel tasks can wait concurrently, so the sum can exceed the request's elapsed duration. Do not interpret it as a stopwatch reading for the query.
Use the required diagnostic permissions for these views. On SQL Server 2022 and later, server-wide diagnostic access uses VIEW SERVER PERFORMANCE STATE for relevant server DMVs. Follow your approved permissions process rather than broadening an application login.
Capture a Baseline Around a Parallel Candidate
Create the sample in a disposable database with compatibility level 160 or higher. GENERATE_SERIES is available starting with SQL Server 2022. Its range below describes generated input, not a measured workload result.
SELECT value AS ItemID, value % 100 AS GroupID,
value % 1000 AS Amount
INTO #ParallelWaitDemo
FROM GENERATE_SERIES(1, 300000);
SELECT wait_type, waiting_tasks_count, wait_time_ms
INTO #WaitBefore
FROM sys.dm_exec_session_wait_stats
WHERE session_id = @@SPID;
SET STATISTICS TIME ON;
SELECT GroupID, SUM(CONVERT(bigint, Amount)) AS GroupAmount
FROM #ParallelWaitDemo
GROUP BY GroupID
ORDER BY GroupAmount DESC
OPTION (MAXDOP 4);
SET STATISTICS TIME OFF;Enable the actual plan before running the aggregate. MAXDOP 4 allows at most four workers for parallel regions but does not force a parallel plan. The optimizer still decides whether parallel execution is worth its cost.
On my test instance, this small aggregate stayed serial because its estimated cost was below the cost threshold for parallelism. The session delta then showed no new CX waits. If the plan is serial, do not claim that this run demonstrates exchange waits. Inspect its cost and shape, then choose a representative parallel query on your test database. An example's intended plan is not an observed result.

Read the CXSYNC_PORT Session Delta
Subtract the stored baseline after the candidate finishes. New wait types need a zero baseline. Keep the session unchanged so the two snapshots describe the same connection and its intervening work.
SELECT a.wait_type,
a.waiting_tasks_count - COALESCE(b.waiting_tasks_count, 0) AS NewWaits,
a.wait_time_ms - COALESCE(b.wait_time_ms, 0) AS NewWaitMs
FROM sys.dm_exec_session_wait_stats AS a
LEFT JOIN #WaitBefore AS b ON b.wait_type = a.wait_type
WHERE a.session_id = @@SPID AND a.wait_type LIKE N'CX%'
ORDER BY NewWaitMs DESC;The delta covers everything done between the snapshots, including diagnostic work. Keep that interval narrow and avoid unrelated statements. A clean dedicated query window makes the comparison easier to explain.
A zero delta is a valid result. It means those recorded categories did not accumulate measurable time in this test interval. It does not prove the same query will never synchronize under another distribution or degree of parallelism.
Inspect Exchanges and Per-Thread Rows
Locate the Parallelism operators in the actual plan. Read whether each exchange repartitions, distributes, or gathers streams. The workers around those operators can receive different amounts of data depending on keys and upstream filters.
Inspect per-thread runtime rows on scans, joins, and exchanges where the viewer exposes them. Compare workers within the same parallel region. The coordinator thread has a different role, so its count is not another identical worker assignment.
I look for the operator that makes the last worker finish late. A skewed join key, a spill, or a blocking sort provides a concrete direction for investigation. A large synchronization total alone does not explain that cause.
Check estimates and memory grants alongside runtime rows. An under-sized grant can produce a spill, and inaccurate estimates can shape the join or exchange choice. Preserve those details when recording the wait delta.
Compare CXSYNC_PORT Under a Query-Level MAXDOP
Reset only your local baseline table before another run. Do not clear server-wide wait statistics to make the report look cleaner. The next query tests serial execution while preserving the same result definition.
TRUNCATE TABLE #WaitBefore;
INSERT #WaitBefore
SELECT wait_type, waiting_tasks_count, wait_time_ms
FROM sys.dm_exec_session_wait_stats WHERE session_id = @@SPID;
SET STATISTICS TIME ON;
SELECT GroupID, SUM(CONVERT(bigint, Amount)) AS GroupAmount
FROM #ParallelWaitDemo
GROUP BY GroupID
ORDER BY GroupAmount DESC
OPTION (MAXDOP 1);
SET STATISTICS TIME OFF;Run the delta query again and keep both actual plans and timing messages. Also test another approved query-level degree when appropriate. Repeated comparable executions give more useful evidence than one warm run against one cold run.
Fewer synchronization waits do not guarantee a faster query. Serial execution removes parallel exchanges but can take longer to perform the remaining work. Compare elapsed duration, CPU, and the broader workload effects together.
Keep the Server Setting Out of a Single-Query Verdict
Which outcome matters to the application: a smaller wait counter or a predictable completion time? Treat wait statistics as clues supporting that outcome. The scoreboard does not get faster because one category disappears from it.
Preserve server-wide MAXDOP while diagnosing the selected request. Changing it affects unrelated queries, maintenance, and concurrency. A server-wide recommendation needs representative workload evidence and a separate reviewed decision.
Document the selected query, its inputs, the wait deltas, and the important plan properties. That record explains whether synchronization reflected normal coordination or a specific expensive operator worth correcting.
Related reading on this blog: Parallelism and Threads with No Work and NonParallelPlanReason: Why a Query Refuses to Go Parallel.

A parallel synchronization wait is not a diagnosis, it is a clue pointing toward the work its threads must coordinate.
Published by Pinal Dave on SQLAuthority. More of my work at pinaldave.com.




