Quick Answer
HADR_DATABASE_WAIT_FOR_TRANSITION_TO_VERSIONING occurs when readable secondary replicas block queries until all pre-existing transactions complete, ensuring row versioning works correctly for snapshot isolation. This wait typically appears during secondary replica initialization and usually resolves automatically within minutes.
Root Cause Analysis
When a secondary replica transitions to allow read workloads, SQL Server must guarantee that the version store contains all necessary row versions for snapshot isolation queries. The lock manager coordinates with the transaction log manager to track all transactions that were active when read access was enabled. These in-flight transactions must either commit or rollback before new snapshot isolation queries can execute safely.
The wait occurs in the scheduler when the query execution engine attempts to begin a snapshot isolation transaction but discovers that the secondary replica's version store may be incomplete. The buffer pool manager holds query execution until the transaction coordinator confirms all pre-transition transactions have completed. This mechanism prevents snapshot isolation queries from reading inconsistent data or encountering missing row versions.
SQL Server 2016 introduced improvements to this process by reducing the transition window through better coordination between the primary and secondary replicas. SQL Server 2019 enhanced the version store cleanup process, reducing the duration of these waits. SQL Server 2022 added more granular tracking of transaction states, further minimizing wait times during replica initialization.
The wait specifically protects against scenarios where a transaction began before read workloads were enabled but hasn't yet written its changes to the version store on the secondary replica. Without this coordination, snapshot queries could return incorrect results or encounter version store corruption.
AutoDBA checks Always On availability group health, replica synchronization status, and version store configuration across your entire SQL Server instance in 60 seconds. Download the free diagnostic script and see what else needs attention.
Diagnostic Queries
-- Check current HADR wait statistics and duration
SELECT
wait_type,
waiting_tasks_count,
wait_time_ms,
max_wait_time_ms,
signal_wait_time_ms
FROM sys.dm_os_wait_stats
WHERE wait_type = 'HADR_DATABASE_WAIT_FOR_TRANSITION_TO_VERSIONING';
-- Identify which databases and replicas are experiencing the wait
SELECT
ar.replica_server_name,
adc.database_name,
drs.synchronization_state_desc,
arep.secondary_role_allow_connections_desc,
drs.log_send_queue_size,
drs.redo_queue_size
FROM sys.dm_hadr_database_replica_states drs
INNER JOIN sys.dm_hadr_availability_replica_states ar
ON drs.replica_id = ar.replica_id
INNER JOIN sys.availability_replicas arep
ON drs.replica_id = arep.replica_id
INNER JOIN sys.availability_databases_cluster adc
ON drs.group_id = adc.group_id AND drs.database_id = adc.database_id
WHERE arep.secondary_role_allow_connections_desc IN ('READ_ONLY', 'ALL');
-- Monitor active transactions that may be blocking the transition
SELECT
s.session_id,
s.login_name,
s.program_name,
t.transaction_begin_time,
t.transaction_type,
t.transaction_state,
DATEDIFF(SECOND, t.transaction_begin_time, GETDATE()) AS duration_seconds
FROM sys.dm_tran_active_transactions t
INNER JOIN sys.dm_tran_session_transactions st ON t.transaction_id = st.transaction_id
INNER JOIN sys.dm_exec_sessions s ON st.session_id = s.session_id
WHERE t.transaction_begin_time < DATEADD(MINUTE, -5, GETDATE())
ORDER BY t.transaction_begin_time;
-- Check version store usage and cleanup status
SELECT
DB_NAME() as database_name,
version_store_reserved_page_count * 8 / 1024 AS version_store_mb,
version_store_reserved_page_count,
version_cleanup_rate_bytes_per_sec / 1024 / 1024 AS cleanup_rate_mb_per_sec
FROM sys.dm_tran_version_store_space_usage;
-- Monitor current blocked queries waiting on this condition
SELECT
r.session_id,
r.wait_type,
r.wait_time,
r.last_wait_type,
s.program_name,
s.login_name,
t.text
FROM sys.dm_exec_requests r
INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE r.wait_type = 'HADR_DATABASE_WAIT_FOR_TRANSITION_TO_VERSIONING';
Fix Scripts
Kill Long-Running Blocking Transactions Terminates transactions that have been running since before the replica transition and are preventing read access initialization.
-- WARNING: Test in development first. This kills active transactions.
-- Identify and kill transactions older than 10 minutes during transition
DECLARE @sql NVARCHAR(MAX) = '';
SELECT @sql = @sql + 'KILL ' + CAST(s.session_id AS VARCHAR(10)) + ';' + CHAR(13)
FROM sys.dm_tran_active_transactions t
INNER JOIN sys.dm_tran_session_transactions st ON t.transaction_id = st.transaction_id
INNER JOIN sys.dm_exec_sessions s ON st.session_id = s.session_id
WHERE t.transaction_begin_time < DATEADD(MINUTE, -10, GETDATE())
AND s.is_user_process = 1;
-- Review the generated kill statements before executing
PRINT @sql;
-- EXEC sp_executesql @sql;
Monitor Version Store Cleanup Version store cleanup is handled automatically by a background task. Monitor cleanup progress and ensure it is keeping up.
-- Monitor version store usage and cleanup progress
-- Run on secondary replica experiencing the wait
SELECT
DB_NAME(database_id) AS database_name,
version_store_reserved_page_count * 8 / 1024 AS version_store_mb,
version_store_reserved_page_count
FROM sys.dm_tran_version_store_space_usage
ORDER BY version_store_reserved_page_count DESC;
-- Check for long-running transactions blocking version store cleanup
SELECT
t.transaction_id,
t.transaction_begin_time,
s.session_id,
s.login_name,
DATEDIFF(SECOND, t.transaction_begin_time, GETDATE()) AS duration_seconds
FROM sys.dm_tran_active_transactions t
INNER JOIN sys.dm_tran_session_transactions st ON t.transaction_id = st.transaction_id
INNER JOIN sys.dm_exec_sessions s ON st.session_id = s.session_id
ORDER BY t.transaction_begin_time;
Restart Secondary Replica Role Resets the replica transition state when waits persist abnormally long.
-- WARNING: This briefly makes the secondary unavailable for reads
-- Execute on primary replica to restart secondary read capability
ALTER AVAILABILITY GROUP [YourAGName]
MODIFY REPLICA ON 'SecondaryServerName'
WITH (SECONDARY_ROLE(ALLOW_CONNECTIONS = NO));
-- Wait 30 seconds for connections to clear
WAITFOR DELAY '00:00:30';
ALTER AVAILABILITY GROUP [YourAGName]
MODIFY REPLICA ON 'SecondaryServerName'
WITH (SECONDARY_ROLE(ALLOW_CONNECTIONS = READ_ONLY));
Increase Version Store Space Ensures adequate tempdb space for version store operations during transitions.
-- Expand tempdb to accommodate version store requirements
-- Calculate recommended size based on workload
SELECT
name,
size * 8 / 1024 AS current_size_mb,
(size * 8 / 1024) * 1.5 AS recommended_size_mb
FROM sys.master_files
WHERE database_id = 2 AND type = 0;
-- Resize tempdb data files (adjust file names and sizes appropriately)
ALTER DATABASE tempdb
MODIFY FILE (NAME = tempdev, SIZE = 2048MB);
AutoDBA generates fix scripts like these automatically, with impact estimates and rollback SQL included.
Prevention
Configure secondary replicas with SECONDARY_ROLE(ALLOW_CONNECTIONS = READ_ONLY) only after ensuring adequate tempdb sizing for version store operations. Allocate at least 25% of your largest table size for tempdb initial sizing on readable secondaries.
Implement connection retry logic in applications querying readable secondaries to handle brief unavailability during replica transitions. Use connection timeouts of at least 60 seconds when connecting to readable secondaries immediately after failover events.
Monitor long-running transactions on primary replicas that can delay secondary replica initialization. Establish alerts when transactions exceed 300 seconds during maintenance windows or availability group operations. Configure READ_COMMITTED_SNAPSHOT ON for databases participating in availability groups to reduce lock conflicts during transitions.
Schedule availability group maintenance during low-transaction periods to minimize the number of in-flight transactions that must complete before secondary replicas become readable. Consider using delayed durability for non-critical transactions during peak periods to reduce version store pressure.
Set up automated monitoring for version store space usage and cleanup rates on secondary replicas. Alert when version store usage exceeds 1GB or cleanup rates drop below expected thresholds during normal operations.
Need hands-on help?
Dealing with persistent hadr_database_wait_for_transition_to_versioning issues across your environment? Samix Technology provides hands-on SQL Server performance consulting with 15+ years of production DBA experience.