Availability Group Health Troubleshooting

Use this when an availability database shows Not Synchronizing or Suspended, when the AG dashboard shows a warning, or when log_reuse_wait_desc is AVAILABILITY_REPLICA (see Transaction Log Full).

Step 1: State of every replica

SELECT ag.name AS ag_name, ar.replica_server_name, ars.role_desc,
       ars.connected_state_desc, ars.synchronization_health_desc
FROM sys.dm_hadr_availability_replica_states ars
JOIN sys.availability_replicas ar ON ars.replica_id = ar.replica_id
JOIN sys.availability_groups ag ON ars.group_id = ag.group_id;

Step 2: State and queues for each database (run on the primary)

SELECT ar.replica_server_name, DB_NAME(drs.database_id) AS database_name,
       drs.synchronization_state_desc, drs.synchronization_health_desc,
       drs.is_suspended, drs.suspend_reason_desc,
       drs.log_send_queue_size AS log_send_queue_kb,
       drs.redo_queue_size AS redo_queue_kb,
       drs.last_hardened_time, drs.last_redone_time
FROM sys.dm_hadr_database_replica_states drs
JOIN sys.availability_replicas ar ON drs.replica_id = ar.replica_id
ORDER BY database_name, ar.replica_server_name;

Step 3: Read the result

  • is_suspended = 1: data movement is suspended. SUSPEND_FROM_USER means someone suspended it; any other suspend_reason_desc means SQL Server suspended it after an error, so check the SQL Server error log on that replica before resuming.
  • Large log_send_queue_kb: the primary cannot send log fast enough, usually because of the network or a disconnected secondary. The primary’s log cannot be reused until the log has been sent.
  • Large redo_queue_kb: the secondary has received the log but is slow to apply it, usually because of slow storage on the secondary or long-running reads on a readable secondary.
  • connected_state_desc = DISCONNECTED: check the endpoint and the network between the replicas (Step 4).

Step 4: Check the mirroring endpoint on each replica

SELECT e.name, e.state_desc, e.role_desc, t.port
FROM sys.database_mirroring_endpoints e
JOIN sys.tcp_endpoints t ON e.endpoint_id = t.endpoint_id;

state_desc should be STARTED on every replica, and the port (normally 5022) must be open in both directions between the servers.

Step 5: Resume data movement (NEEDS APPROVAL)

-- Run on the replica where the database is suspended
ALTER DATABASE [YourDB] SET HADR RESUME;

Resume only once you know why it was suspended. Rollback: ALTER DATABASE [YourDB] SET HADR SUSPEND; If it suspends again straight away, the error log on that replica will show the reason.

Also check

  • The AlwaysOn_health Extended Events session and the SQL Server error log on each replica.
  • The Windows cluster in Failover Cluster Manager (see Quorum Failure).
  • Disk space on the secondaries. If a data or log file cannot grow on a secondary, that database suspends.

From my SQL Server DBA handbook.