DBA Scripts: Get Mirroring Endpoint Health and Status

🔧Part of the DBA-Tools Project, copy/paste SQL Server scripts and health checks.In: High Availability

Still Running Database Mirroring? Here’s What to Check

Database Mirroring has been deprecated since SQL Server 2012, and Always On Availability Groups are the replacement for any new deployment. Deprecated doesn’t mean gone though. Plenty of instances still run it, migrations to AG take time, and a mirror that is still running needs the same two questions answered as any HA feature: can the two sides talk to each other, and is the mirror caught up?

Mirroring Endpoint Health checks the first question: the endpoint’s state, port, and authentication configuration, since if the endpoint isn’t STARTED, nothing else here matters. Mirroring Status checks the second: operating mode, mirroring state, and point-in-time send/redo queue latency for every mirrored database.


Why Mirroring Endpoint Health and Status Matter

  • An endpoint that isn’t STARTED breaks mirroring communication entirely, and it’s the first thing to check before troubleshooting anything else about a “disconnected” mirror
  • mirroring_state separates a mirror that is caught up, one that is catching up, one that was paused on purpose and one that is broken, four situations that look much the same from a distance
  • High Safety with a witness gives automatic failover and High Performance does not, so knowing which one is configured changes what “the mirror is behind” means for risk
  • If you’re planning a migration away from mirroring to Availability Groups, knowing exactly what’s configured now is the starting point

When to Run These Scripts

  • Any environment still running Database Mirroring, as a routine health check
  • Troubleshooting a mirror reported as Disconnected, start with endpoint health before assuming a data problem
  • Before planning a migration off mirroring to Availability Groups, to document the current configuration accurately
  • After any network change between the principal and mirror servers, to confirm the endpoint still communicates

The Scripts

Get-MirroringEndpointHealth: Can the Two Sides Talk?

✓ Verified
  • Tested on: SQL Server 2025 (RTM CU8, 17.0.4075.5), Windows lab instance
  • Last verified: 2026-10-23 (both scripts run on the lab, which has no mirroring configured: the endpoint script returned its status row and the status script returned no rows)
  • Permissions: Get-MirroringEndpointHealth: VIEW SERVER STATE · Get-MirroringStatus: VIEW SERVER STATE, VIEW DATABASE STATE
  • Safety: read-only, impact low
/*
Script Name : Get-MirroringEndpointHealth
Category    : high-availability
Purpose     : Returns the state, port, role, and authentication configuration of the database
              mirroring endpoint. If the endpoint is not STARTED, mirroring cannot communicate.
              Run on both the principal and mirror server during troubleshooting.
Author      : Peter Whyte (https://sqldba.blog/dba-scripts-get-mirroring-endpoint-health-and-status/)
Requires    : VIEW SERVER STATE
HealthCheck : Yes
*/
-- SAFE:ReadOnly
-- IMPACT:Low
SET NOCOUNT ON;

IF NOT EXISTS (SELECT 1 FROM sys.database_mirroring_endpoints)
BEGIN
    SELECT 'No database mirroring/AG endpoint exists on this instance.' AS status;
END
ELSE
BEGIN
    SELECT
        e.name AS endpoint_name,
        e.state_desc AS endpoint_state,
        d.role_desc AS endpoint_role,
        tcp.port AS port_number,
        d.connection_auth_desc AS connection_auth,
        d.encryption_algorithm_desc AS encryption_algorithm
    FROM sys.endpoints e
    JOIN sys.database_mirroring_endpoints d ON d.endpoint_id = e.endpoint_id
    JOIN sys.tcp_endpoints tcp ON tcp.endpoint_id = e.endpoint_id;
END

If no endpoint exists at all, the script returns one status row saying so. That is a different finding from an endpoint that exists but isn’t STARTED: the first means mirroring was never set up here, the second means it was and the endpoint is down.

Get-MirroringStatus: Is the Mirror Caught Up?

/*
Script Name : Get-MirroringStatus
Category    : high-availability
Purpose     : Shows health, state, and point-in-time latency for all mirrored databases on this
              instance. Run on the principal server. Reports operating mode, mirroring state,
              database size, log send queue, and redo queue.
              Note: Database Mirroring has been deprecated since SQL Server 2012. Always On
              Availability Groups are the supported replacement for new deployments.
Author      : Peter Whyte (https://sqldba.blog/dba-scripts-get-mirroring-endpoint-health-and-status/)
Requires    : VIEW SERVER STATE, VIEW DATABASE STATE
*/
-- SAFE:ReadOnly
-- IMPACT:Low
SET NOCOUNT ON;

SELECT
    CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(256)) AS principal_server,
    m.mirroring_partner_instance AS mirror_server,
    DB_NAME(m.database_id) AS database_name,
    CAST(SUM(f.size * 8 / 1024.0 / 1024) AS DECIMAL(10,1)) AS database_size_gb,
    CASE m.mirroring_safety_level
        WHEN 1 THEN 'High Performance'
        WHEN 2 THEN 'High Safety'
        ELSE 'Unknown'
    END AS operating_mode,
    CASE m.mirroring_state
        WHEN 0 THEN 'Suspended'
        WHEN 1 THEN 'Disconnected'
        WHEN 2 THEN 'Synchronizing'
        WHEN 3 THEN 'Pending Failover'
        WHEN 4 THEN 'Synchronized'
        ELSE 'Unknown'
    END AS mirroring_state,
    m.mirroring_role_desc AS role,
    m.mirroring_witness_name AS witness_server,
    perf.log_send_queue_kb,
    perf.redo_queue_kb,
    RIGHT(
        m.mirroring_partner_name,
        CHARINDEX(':', REVERSE(m.mirroring_partner_name) + ':') - 1
    ) AS endpoint_port
FROM sys.database_mirroring m
JOIN sys.master_files f ON f.database_id = m.database_id
OUTER APPLY (
    SELECT
        MAX(CASE WHEN counter_name = N'Log Send Queue KB' THEN cntr_value END) AS log_send_queue_kb,
        MAX(CASE WHEN counter_name = N'Redo Queue KB' THEN cntr_value END) AS redo_queue_kb
    FROM sys.dm_os_performance_counters
    WHERE object_name LIKE N'%Database Mirroring%'
      AND instance_name = DB_NAME(m.database_id)
) perf
WHERE m.mirroring_guid IS NOT NULL
  AND m.mirroring_role_desc = N'PRINCIPAL'
GROUP BY
    m.database_id,
    m.mirroring_partner_instance,
    m.mirroring_safety_level,
    m.mirroring_state,
    m.mirroring_role_desc,
    m.mirroring_partner_name,
    m.mirroring_witness_name,
    perf.log_send_queue_kb,
    perf.redo_queue_kb
ORDER BY DB_NAME(m.database_id);

Run it on the principal. The mirroring_role_desc = 'PRINCIPAL' filter is deliberate, so a database shows once and running it on the mirror returns no rows.


How To Run From The Repo

Clone DBA Tools, initialize and run either script:

# Clone dba-tools repo:
git clone https://github.com/peterwhyte-lgtm/dba-tools

# Initialize environment:
cd dba-tools
.\Initialize-Environment.ps1

# Mirroring endpoint state, port, and authentication:
.\run.ps1 Get-MirroringEndpointHealth

# Mirroring state and queue latency, run on the principal:
.\run.ps1 Get-MirroringStatus

# To run against a remote sql server:
.\run.ps1 Get-MirroringStatus -ServerInstance SQLSERVER01

These scripts live in the repo at:


Example Output

My lab has never had mirroring configured, so Get-MirroringEndpointHealth returns its status row, No database mirroring/AG endpoint exists on this instance., and Get-MirroringStatus returns no rows because no database has a mirroring_guid. That is the correct answer for an instance that has never used Database Mirroring. On an instance with mirroring configured, Get-MirroringStatus returns a row like this (key columns shown):

principal_server mirror_server database_name operating_mode mirroring_state witness_server log_send_queue_kb redo_queue_kb
SQLPROD01 SQLPROD02 OrdersDB High Safety Synchronized SQLWITNESS01 0 0

Understanding the Results

Get-MirroringEndpointHealth

One row per database mirroring endpoint, which on most instances means one row.

status
Only returned when no mirroring or AG endpoint exists on the instance. It replaces every other column: mirroring has never been set up here.
endpoint_name
The endpoint’s name, often Mirroring or Hadr_endpoint. The view covers both features, so an Availability Group endpoint shows here too.
endpoint_state
STARTED, STOPPED or DISABLED. Anything other than STARTED and the partners cannot talk at all.Act whenCheck this first on a disconnected mirror, on both servers. A stopped endpoint and a data problem need completely different fixes.
endpoint_role
PARTNER, WITNESS or ALL. A witness server’s endpoint reads WITNESS; a partner configured as WITNESS only cannot carry a mirroring session.
port_number
The TCP port the endpoint listens on, usually 5022, the port the setup wizards suggest. It has to be open through every firewall between the partners and the witness.WatchCompare it with endpoint_port from the status script. A partner pointing at a different port than the one listening is a classic cause of error 1418.
connection_auth
encryption_algorithm
How partners authenticate (NEGOTIATE, KERBEROS, CERTIFICATE and combinations) and how the traffic is encrypted. Both sides must be compatible or the connection is refused.WatchAn RC4 value is backward compatibility only. Plan the move to AES alongside any migration off mirroring.

Get-MirroringStatus

One row per mirrored database where this server is the principal.

principal_server
mirror_server
The instance you ran it on and the partner instance it mirrors to.
database_name
database_size_gb
The mirrored database and its total size across data and log files. Size is a rough guide to how long a reinitialise from backup would take if the mirror has to be rebuilt.
operating_mode
High Safety is synchronous: a commit waits for the mirror. High Performance is asynchronous: the principal does not wait, so the mirror can fall behind and a forced failover can lose data.
mirroring_state
Synchronized is caught up. Synchronizing is catching up. Suspended was paused, usually by a person before maintenance, and stays paused until resumed. Disconnected means the partners cannot reach each other right now. Pending Failover is a failover in progress. Unknown is any raw state the script does not name.Act whenDisconnected: check the endpoint on both sides, then the network. Suspended: find out who paused it and why before resuming.
role
Always PRINCIPAL, because the script filters to that side.
witness_server
The witness, or NULL when there is none. High Safety without a witness is still synchronous but fails over manually only.WatchHigh Safety with NULL here means nobody gets automatic failover, whatever the safety level suggests.
log_send_queue_kb
Log on the principal that has not yet been sent to the mirror, read from the Database Mirroring performance counters at the moment you run it.WatchOne high reading can be a burst. Run it again a few minutes later; a number that keeps growing is a mirror falling behind.
redo_queue_kb
Log the mirror has hardened but not yet applied. The mirror reports it back to the principal. A large redo queue lengthens a failover, because the mirror has to finish redo before it can come online.
endpoint_port
The port the principal uses to reach the partner, taken from the end of mirroring_partner_name (TCP://host:port).

Best Practices

  • Check endpoint health first when a mirror looks disconnected, a communication problem and a data problem need completely different fixes
  • Don’t assume Suspended means broken, it’s a deliberate, reversible pause, resume it explicitly once the reason for suspending has passed
  • If planning a migration to Availability Groups, capture this output as your documented starting configuration before making changes
  • Treat any growing redo_queue_kb on a Synchronizing mirror the same as a growing AG redo queue, a real, worsening lag, not a stable steady-state

Microsoft Learn: sys.database_mirroring · sys.database_mirroring_endpoints · Database Mirroring performance counters


Frequently Asked Questions

Is Database Mirroring still supported?

It has been deprecated since SQL Server 2012 and still works in current versions, including SQL Server 2025. Microsoft’s guidance is to use Always On Availability Groups for anything new; mirroring remains for environments that haven’t migrated yet.

Why does Get-MirroringStatus filter to the PRINCIPAL role only?

On the mirror the same pairing shows with the role MIRROR, and its values are only visible to a sysadmin. Filtering to PRINCIPAL keeps one row per mirrored database. Run it on whichever server is the principal right now; on the mirror it returns no rows.


Summary

A deprecated feature still in production needs the same two questions answered as any HA technology: can the two sides communicate, and are they actually in sync? These two scripts answer both, endpoint health first since nothing else matters if the endpoint isn’t started, then mirroring state and queue latency for whatever’s actually configured.

Run both as a routine check on any instance still using Database Mirroring, and treat a growing queue or a disconnected endpoint with the same urgency you’d give the equivalent AG finding.


Related

You may also find these useful:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *