Quick Answer
XACT_OWN_TRANSACTION occurs when a session waits to acquire ownership of a transaction that is being transferred between sessions or contexts. This typically happens during distributed transactions, Service Broker message processing, or when transactions are passed between application tiers. Medium severity because it indicates transaction coordination overhead that can impact throughput.
Root Cause Analysis
This wait type surfaces when SQL Server's transaction manager must coordinate transaction ownership transfers between different execution contexts. The transaction manager maintains ownership records in sys.dm_tran_locks and sys.dm_tran_active_transactions, and when ownership changes hands, the acquiring session enters this wait state.
Most commonly occurs in three scenarios: distributed transactions coordinated by MS DTC where transaction ownership transfers from the coordinator to participating resource managers; Service Broker conversations where message processing requires transaction context changes between the broker service and user code; and application architectures using connection pooling with transaction scope preservation where pooled connections inherit existing transaction contexts.
The wait happens at the lock manager level when the new owner must acquire exclusive access to the transaction object in the transaction descriptor table. SQL Server 2016 introduced improvements to transaction descriptor locking that reduced wait times in high-concurrency scenarios. SQL Server 2019 further optimized this by implementing lock-free transaction descriptor lookups for read operations, though ownership transfers still require exclusive access.
In SQL Server 2022, the introduction of contained availability groups changed how distributed transaction ownership transfers occur across replicas, potentially increasing these waits during failover scenarios. The wait duration directly correlates with the complexity of the transaction's lock hierarchy and the number of resources already owned by the transaction being transferred.
AutoDBA checks distributed transaction timeout settings, Service Broker conversation health, and transaction scope monitoring across your entire SQL Server instance in 60 seconds. Download the free diagnostic script and see what else needs attention.
Diagnostic Queries
-- Current sessions experiencing XACT_OWN_TRANSACTION waits
SELECT
s.session_id,
r.wait_type,
r.wait_time,
r.blocking_session_id,
s.login_name,
s.program_name,
t.text AS current_sql,
at.transaction_id,
at.transaction_state,
at.transaction_type
FROM sys.dm_exec_requests r
JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
LEFT JOIN sys.dm_tran_session_transactions st ON s.session_id = st.session_id
LEFT JOIN sys.dm_tran_active_transactions at ON st.transaction_id = at.transaction_id
WHERE r.wait_type = 'XACT_OWN_TRANSACTION';
-- Historical wait statistics for transaction ownership waits
SELECT
wait_type,
waiting_tasks_count,
wait_time_ms,
max_wait_time_ms,
signal_wait_time_ms,
wait_time_ms / NULLIF(waiting_tasks_count, 0) AS avg_wait_time_ms
FROM sys.dm_os_wait_stats
WHERE wait_type = 'XACT_OWN_TRANSACTION'
AND waiting_tasks_count > 0;
-- Active distributed transactions that might cause ownership waits
SELECT
dt.transaction_id,
dt.transaction_uow,
dt.transaction_state,
dt.dtc_state,
s.session_id,
s.login_name,
s.program_name,
r.command,
r.wait_type
FROM sys.dm_tran_distributed_transactions dt
JOIN sys.dm_tran_session_transactions st ON dt.transaction_id = st.transaction_id
JOIN sys.dm_exec_sessions s ON st.session_id = s.session_id
LEFT JOIN sys.dm_exec_requests r ON s.session_id = r.session_id
WHERE dt.transaction_state IN (2, 3, 4); -- Active, prepared, or committing states
-- Service Broker conversations with transaction context
SELECT
c.conversation_handle,
c.state_desc,
c.is_initiator,
s.name AS service_name,
q.name AS queue_name,
st.session_id,
at.transaction_id,
at.transaction_state
FROM sys.conversation_endpoints c
JOIN sys.services s ON c.service_id = s.service_id
JOIN sys.service_queues q ON s.service_queue_id = q.object_id
LEFT JOIN sys.dm_tran_session_transactions st ON st.session_id IN (
SELECT session_id FROM sys.dm_exec_requests WHERE command LIKE '%BROKER%'
)
LEFT JOIN sys.dm_tran_active_transactions at ON st.transaction_id = at.transaction_id
WHERE c.state NOT IN ('CO', 'CD'); -- Not closed or disconnected
-- Lock information for transactions experiencing ownership waits
SELECT
tl.request_session_id,
tl.resource_type,
tl.resource_database_id,
tl.resource_associated_entity_id,
tl.request_mode,
tl.request_status,
at.transaction_id,
at.transaction_begin_time,
DATEDIFF(second, at.transaction_begin_time, GETDATE()) AS transaction_duration_sec
FROM sys.dm_tran_locks tl
JOIN sys.dm_tran_active_transactions at ON tl.request_owner_id = at.transaction_id
WHERE tl.request_session_id IN (
SELECT session_id FROM sys.dm_exec_requests WHERE wait_type = 'XACT_OWN_TRANSACTION'
)
ORDER BY transaction_duration_sec DESC;
Fix Scripts
Identify and resolve long-running distributed transactions
-- Kill problematic distributed transactions after review
-- WARNING: Test in dev first, may cause rollbacks
DECLARE @transaction_id BIGINT;
DECLARE @session_id INT;
SELECT TOP 1
@transaction_id = at.transaction_id,
@session_id = st.session_id
FROM sys.dm_tran_active_transactions at
JOIN sys.dm_tran_session_transactions st ON at.transaction_id = st.transaction_id
JOIN sys.dm_tran_distributed_transactions dt ON at.transaction_id = dt.transaction_id
WHERE DATEDIFF(minute, at.transaction_begin_time, GETDATE()) > 30
AND dt.transaction_state = 2; -- Active state
IF @session_id IS NOT NULL
BEGIN
PRINT 'Killing session ' + CAST(@session_id AS VARCHAR(10)) + ' with transaction ' + CAST(@transaction_id AS VARCHAR(20));
-- KILL @session_id; -- Uncomment after verification
END;
Force Service Broker conversation cleanup
-- End conversations that may be holding transaction ownership
-- Use with caution: will terminate active Service Broker dialogs
DECLARE @conversation_handle UNIQUEIDENTIFIER;
DECLARE cleanup_cursor CURSOR FOR
SELECT conversation_handle
FROM sys.conversation_endpoints
WHERE state_desc IN ('CONVERSING', 'STARTED_OUTBOUND', 'STARTED_INBOUND')
AND DATEDIFF(hour, date_created, GETDATE()) > 24;
OPEN cleanup_cursor;
FETCH NEXT FROM cleanup_cursor INTO @conversation_handle;
WHILE @@FETCH_STATUS = 0
BEGIN
BEGIN TRY
END CONVERSATION @conversation_handle WITH CLEANUP;
PRINT 'Ended conversation: ' + CAST(@conversation_handle AS VARCHAR(50));
END TRY
BEGIN CATCH
PRINT 'Failed to end conversation: ' + CAST(@conversation_handle AS VARCHAR(50)) + ' - ' + ERROR_MESSAGE();
END CATCH;
FETCH NEXT FROM cleanup_cursor INTO @conversation_handle;
END;
CLOSE cleanup_cursor;
DEALLOCATE cleanup_cursor;
Configure MS DTC timeout settings
MSDTC timeout settings should not be modified from T-SQL. Instead, configure them through Windows Component Services or PowerShell on the host operating system:
- In Component Services (dcomcnfg.exe), navigate to Component Services > Computers > My Computer > Distributed Transaction Coordinator > Local DTC. Right-click, choose Properties, and adjust values on the Transaction tab (for example, set the Maximum Timeout to 300 seconds).
- Alternatively, use the PowerShell
MsDtcmodule cmdlets (Get-DtcTransactionsTraceSetting,Set-DtcTransaction, and related cmdlets) to script configuration changes across servers.
After changing MSDTC settings, restart the Distributed Transaction Coordinator service and the SQL Server service for the new values to take effect. Always validate changes in a non-production environment first, and coordinate with application owners since shorter timeouts will abort long-running distributed transactions.
Implement transaction scope monitoring
-- Create alert for excessive XACT_OWN_TRANSACTION waits
-- Deploy as SQL Agent job running every 5 minutes
IF NOT EXISTS (SELECT name FROM msdb.dbo.sysalerts WHERE name = 'High XACT_OWN_TRANSACTION Waits')
BEGIN
EXEC msdb.dbo.sp_add_alert
@name = N'High XACT_OWN_TRANSACTION Waits',
@message_id = 0,
@severity = 0,
@performance_condition = N'SQLServer:Wait Statistics|Average wait time (ms)|XACT_OWN_TRANSACTION|>|1000',
@include_event_description_in = 1,
@job_name = N'Investigate Transaction Ownership Issues';
END;
AutoDBA generates fix scripts like these automatically, with impact estimates and rollback SQL included.
Prevention
Configure MS DTC with appropriate timeout values between 300-600 seconds to prevent indefinite transaction ownership waits. Make these changes through the Component Services MMC snap-in (Local DTC > Properties > Transaction tab) or the PowerShell MsDtc module, then restart the Distributed Transaction Coordinator and SQL Server services.
Design Service Broker applications with explicit conversation lifetime management. Implement conversation_timer events and END CONVERSATION statements with appropriate error handling to prevent orphaned conversations that hold transaction contexts indefinitely.
Avoid transaction scope escalation in connection pooling scenarios by ensuring applications explicitly commit or rollback transactions before returning connections to the pool. Configure connection string parameters like "Enlist=false" when distributed transaction coordination is not required.
Monitor sys.dm_os_wait_stats for XACT_OWN_TRANSACTION accumulation patterns. Establish baseline metrics during normal operations, then alert when wait times exceed 2-3 times the baseline average. This indicates either application design issues or infrastructure problems with MS DTC coordination.
Implement proper exception handling in distributed transaction scenarios. Use TransactionScope with appropriate isolation levels and timeout values in .NET applications. Ensure that database connection lifecycle management aligns with transaction scope boundaries to minimize ownership transfer events.
Consider using Availability Groups with contained databases in SQL Server 2022+ to reduce cross-database distributed transaction requirements that commonly trigger ownership waits during failover scenarios.
Need hands-on help?
Dealing with persistent xact_own_transaction issues across your environment? Samix Technology provides hands-on SQL Server performance consulting with 15+ years of production DBA experience.