A client hit a mirroring error while setting up database mirroring. ALTER DATABASE SET PARTNER failed, and the logs on both servers blamed each other. Their network team opened some ports and it started working. I never found out which ones. At the end of the original post I asked readers how to verify it. This time I built a mirroring endpoint on SQL Server 2025 and worked out the checks myself.

What Each Side Said
On the mirror:
Database Mirroring login attempt by user 'ASIA\SQL_SERVICE.' failed with error:
'Connection handshake failed. Could not send a handshake message because the
connection was closed by peer. State 26.'. [CLIENT: <principal address>]On the principal, at almost the same moment:
Error: 1474, Severity: 16, State: 1.
Database mirroring connection error 4 'An error occurred while receiving data:
'10054(An existing connection was forcibly closed by the remote host.)'.'
for 'TCP://<mirror address>:5022'.Each server says the other one hung up. That is the most useful thing in the two messages. The network connection was made, so the port was open. Then one side decided it did not trust the other, and closed it. 10054 is the Windows code for exactly that. I asked Windows to translate it and got “An existing connection was forcibly closed by the remote host.”
Note the name in the first message: a login by the service account ASIA\SQL_SERVICE. Mirroring partners log in to each other using their service accounts. That is where a handshake usually fails.
Check One: the Endpoint Exists and Is Started
I created a mirroring endpoint on my own instance to see what a healthy one looks like, then dropped it again when I had finished:
CREATE ENDPOINT BlogLabMirroring STATE = STARTED
AS TCP (LISTENER_PORT = 5022)
FOR DATABASE_MIRRORING (ROLE = PARTNER,
AUTHENTICATION = WINDOWS NEGOTIATE,
ENCRYPTION = REQUIRED ALGORITHM AES);Then this query, which you run on both partners and compare:
SELECT e.name, e.state_desc, t.port, e.role_desc,
e.connection_auth_desc, e.is_encryption_enabled, e.encryption_algorithm_desc
FROM sys.database_mirroring_endpoints AS e
JOIN sys.tcp_endpoints AS t ON t.endpoint_id = e.endpoint_id;name state_desc port role_desc connection_auth_desc encryption algorithm
BlogLabMirroring STARTED 5022 PARTNER NEGOTIATE 1 AESLook for three things. STARTED, not STOPPED. The same authentication method on both sides. And encryption settings that can agree. An endpoint that requires AES and one that disables encryption will never shake hands.
Check Two: the Partner’s Account May Connect
This is the one that catches most people, and my own test showed why. Straight after creating the endpoint I asked who was allowed to connect to it:
SELECT pr.name AS grantee, pe.permission_name, pe.state_desc
FROM sys.server_permissions AS pe
JOIN sys.server_principals AS pr ON pr.principal_id = pe.grantee_principal_id
JOIN sys.endpoints AS ep ON ep.endpoint_id = pe.major_id
WHERE pe.class_desc = 'ENDPOINT' AND ep.name = 'BlogLabMirroring';It returned nothing. A new endpoint grants CONNECT to nobody except its owner. If the partner runs under a different service account, that account needs a login and a grant, on both sides. Use your own endpoint’s name. Mirroring and Hadr_endpoint are common ones:
CREATE LOGIN [ASIA\SQL_SERVICE] FROM WINDOWS;
GRANT CONNECT ON ENDPOINT::Mirroring TO [ASIA\SQL_SERVICE];Without that grant, the connection opens and the handshake is refused, which is exactly the pattern in the logs above.
Check Three: the Port, From the Other Server
Test-NetConnection -ComputerName PARTNER -Port 5022On my machine this said True while the endpoint was running. After I dropped it, False. Run it from each partner towards the other. It proves the TCP port is reachable, and nothing more.
What a Stranger Looks Like
Out of curiosity, I opened a plain TCP connection to my endpoint, sent it a sentence of text, and closed it. SQL Server wrote this:
An error occurred in a Service Broker/Database Mirroring transport connection
endpoint, Error: 8474, State: 11. (Near endpoint role: Target, far endpoint address: '')Not a handshake message at all. My text never got far enough to be a login attempt. So a handshake failure that names a real service account, like ASIA\SQL_SERVICE above, tells you something. The two servers are genuinely talking. The problem is who they are, not whether they can reach each other.
Where My Client’s Problem Was
Their network team said ports were blocked towards Active Directory. That fits. With NEGOTIATE authentication, each partner checks the other’s service account with a domain controller before accepting it. If a server cannot reach the domain controller, the connection between the partners works and the handshake still fails. It looks like a mirroring problem. It is really a domain problem.
I could not repeat that part here, because my test machine is not on a domain. The three checks above are what I would run today before calling the network team.
A handshake failure is not a closed port, it is two servers that can reach each other but will not trust each other.
Published by Pinal Dave on SQLAuthority. More of my work at pinaldave.com.
Discover more from SQL Authority with Pinal Dave
Subscribe to get the latest posts sent to your email.





1 Comment. Leave new
Did anyone figure out how to resolve this before reaching out to networking team?