Quick Answer
DTC_ABORT_REQUEST occurs when a session waits to acquire ownership of an MSDTC transaction to abort it while another session still holds the transaction. This wait indicates distributed transaction contention and requires investigation of transaction isolation levels and distributed transaction patterns.
Root Cause Analysis
DTC_ABORT_REQUEST manifests when SQL Server's distributed transaction coordinator (MSDTC) must serialize access to abort a distributed transaction. The wait occurs in the MSDTC worker thread pool when a session attempts to acquire exclusive ownership of a transaction resource that another session currently holds.
The distributed transaction manager maintains transaction state through the MSDTC service, which coordinates transactions across multiple resource managers. When a transaction needs to abort, the requesting session must wait for the current transaction owner to release its hold on the distributed transaction context. This serialization prevents race conditions but creates bottlenecks when multiple sessions attempt to abort the same distributed transaction simultaneously.
SQL Server 2016 introduced enhanced distributed transaction logging that improved visibility into these waits. SQL Server 2019 added better timeout handling for distributed transaction operations, reducing instances where sessions wait indefinitely. SQL Server 2022 improved the MSDTC worker thread efficiency, though the fundamental serialization requirement remains unchanged.
The wait specifically occurs in the transaction abort path when the MSDTC worker session calls into the distributed transaction manager's abort routine. The session remains in this wait state until it can acquire the distributed transaction lock, execute the abort operation, and clean up the transaction context.
AutoDBA checks Distributed transaction timeout settings, MSDTC configuration, and transaction isolation monitoring across your entire SQL Server instance in 60 seconds. Download the free diagnostic script and see what else needs attention.
Diagnostic Queries
-- Check current distributed transaction activity and wait patterns
SELECT
ws.session_id,
ws.wait_type,
ws.wait_duration_ms,
ws.resource_description,
s.program_name,
s.login_name,
t.transaction_begin_time,
t.transaction_type,
t.transaction_state
FROM sys.dm_os_waiting_tasks ws
INNER JOIN sys.dm_exec_sessions s ON ws.session_id = s.session_id
LEFT JOIN sys.dm_tran_session_transactions st ON s.session_id = st.session_id
LEFT JOIN sys.dm_tran_active_transactions t ON st.transaction_id = t.transaction_id
WHERE ws.wait_type = 'DTC_ABORT_REQUEST';
-- Analyze distributed transaction patterns and duration
SELECT
t.transaction_id,
t.transaction_begin_time,
DATEDIFF(second, t.transaction_begin_time, GETDATE()) as duration_seconds,
t.transaction_type,
t.transaction_state,
dt.transaction_uow,
dt.transaction_state as dtc_state,
COUNT(st.session_id) as session_count
FROM sys.dm_tran_active_transactions t
INNER JOIN sys.dm_tran_distributed_transactions dt ON t.transaction_id = dt.transaction_id
LEFT JOIN sys.dm_tran_session_transactions st ON t.transaction_id = st.transaction_id
GROUP BY t.transaction_id, t.transaction_begin_time, t.transaction_type, t.transaction_state,
dt.transaction_uow, dt.transaction_state
ORDER BY duration_seconds DESC;
-- Monitor MSDTC performance counters and service health
SELECT
counter_name,
cntr_value,
cntr_type
FROM sys.dm_os_performance_counters
WHERE object_name LIKE '%Distributed Transaction Coordinator%'
OR (object_name LIKE '%Transactions%' AND counter_name LIKE '%Distributed%');
-- Check for blocking chains involving distributed transactions
WITH blocking_chain AS (
SELECT
session_id,
blocking_session_id,
wait_type,
wait_resource,
wait_time
FROM sys.dm_exec_requests
WHERE blocking_session_id != 0
UNION ALL
SELECT
r.session_id,
r.blocking_session_id,
r.wait_type,
r.wait_resource,
r.wait_time
FROM sys.dm_exec_requests r
INNER JOIN blocking_chain bc ON r.session_id = bc.blocking_session_id
)
SELECT
bc.*,
s.program_name,
s.login_name,
t.transaction_isolation_level,
CASE WHEN dt.transaction_id IS NOT NULL THEN 'Distributed' ELSE 'Local' END as transaction_type
FROM blocking_chain bc
INNER JOIN sys.dm_exec_sessions s ON bc.session_id = s.session_id
LEFT JOIN sys.dm_tran_session_transactions st ON s.session_id = st.session_id
LEFT JOIN sys.dm_tran_active_transactions t ON st.transaction_id = t.transaction_id
LEFT JOIN sys.dm_tran_distributed_transactions dt ON t.transaction_id = dt.transaction_id
WHERE bc.wait_type IN ('DTC_ABORT_REQUEST', 'DTCLOCK') OR dt.transaction_id IS NOT NULL;
Fix Scripts
-- Emergency termination of long-running distributed transactions
-- WARNING: Only use in emergencies, may cause data inconsistency
DECLARE @transaction_id bigint;
DECLARE @session_id int;
-- Identify problematic distributed transactions over 5 minutes old
DECLARE transaction_cursor CURSOR FOR
SELECT DISTINCT t.transaction_id, st.session_id
FROM sys.dm_tran_active_transactions t
INNER JOIN sys.dm_tran_distributed_transactions dt ON t.transaction_id = dt.transaction_id
INNER JOIN sys.dm_tran_session_transactions st ON t.transaction_id = st.transaction_id
WHERE DATEDIFF(minute, t.transaction_begin_time, GETDATE()) > 5;
OPEN transaction_cursor;
FETCH NEXT FROM transaction_cursor INTO @transaction_id, @session_id;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT 'Killing session ' + CAST(@session_id AS VARCHAR(10)) + ' with distributed transaction ' + CAST(@transaction_id AS VARCHAR(20));
-- Uncomment the following line only after careful consideration
-- KILL @session_id;
FETCH NEXT FROM transaction_cursor INTO @transaction_id, @session_id;
END;
CLOSE transaction_cursor;
DEALLOCATE transaction_cursor;
-- Set distributed transaction timeout to prevent indefinite waits
-- This affects future distributed transactions, not current ones
EXEC sp_configure 'remote query timeout', 600; -- 10 minutes
RECONFIGURE;
-- To configure MSDTC timeout settings:
-- Open Component Services (dcomcnfg) manually on the server
-- Navigate to Component Services > Computers > My Computer > Distributed Transaction Coordinator
-- Right-click Local DTC > Properties > Security tab
-- Adjust timeout settings as needed (default 60 seconds)
-- Monitor and alert on excessive DTC_ABORT_REQUEST waits
-- Deploy as a SQL Agent job that runs every 5 minutes
DECLARE @threshold_ms int = 30000; -- 30 seconds
DECLARE @wait_count int;
SELECT @wait_count = COUNT(*)
FROM sys.dm_os_waiting_tasks
WHERE wait_type = 'DTC_ABORT_REQUEST'
AND wait_duration_ms > @threshold_ms;
IF @wait_count > 0
BEGIN
DECLARE @msg NVARCHAR(500) = 'DTC_ABORT_REQUEST wait detected: ' + CAST(@wait_count AS VARCHAR(10)) +
' sessions waiting longer than ' + CAST(@threshold_ms AS VARCHAR(10)) + ' ms';
-- Send alert (customize notification method)
EXEC msdb.dbo.sp_send_dbmail
@profile_name = 'DBA Alerts',
@recipients = 'dba-team@company.com',
@subject = 'DTC Abort Request Alert',
@body = @msg;
END;
AutoDBA generates fix scripts like these automatically, with impact estimates and rollback SQL included.
Prevention
Configure distributed transaction timeouts appropriately using DCOMCNFG to prevent indefinite waits. Set the MSDTC timeout to 60-300 seconds based on your application's transaction patterns. Excessive timeouts allow problematic transactions to persist while very short timeouts cause premature rollbacks.
Implement connection pooling properly in applications to reduce distributed transaction overhead. Each new connection participating in a distributed transaction adds coordination complexity. Use connection string parameters like "Enlist=false" for read-only operations that don't require transactional consistency.
Monitor transaction isolation levels in applications using distributed transactions. SERIALIZABLE and REPEATABLE READ isolation levels hold locks longer, increasing the likelihood of DTC_ABORT_REQUEST waits. Consider READ COMMITTED SNAPSHOT isolation where appropriate to reduce lock contention.
Establish monitoring for long-running distributed transactions using the diagnostic queries above. Deploy automated alerts when distributed transactions exceed reasonable duration thresholds. Set up trend analysis to identify applications that frequently create distributed transaction contention.
Review distributed transaction usage patterns in your applications. Many distributed transactions can be refactored into local transactions or eliminated through architectural changes like message queuing or eventual consistency patterns. Consider implementing saga patterns for complex multi-resource operations instead of two-phase commit transactions.
Need hands-on help?
Dealing with persistent dtc_abort_request issues across your environment? Samix Technology provides hands-on SQL Server performance consulting with 15+ years of production DBA experience.