Mutual TLS, where the client proves its identity with a certificate just as the server does, sounds like a single switch: require client certificates, issue one to each service, done. On Windows it is a negotiation with several moving parts. The server decides whether to ask, whether to hint which issuers it trusts, and how strictly to check what arrives. The client, or Schannel acting for it, decides which certificate to offer, sometimes by searching a store on its own. Each side can fail quietly, and the failures look like ordinary connection errors. This article walks through the mechanics as Microsoft documents them, so that a service or an AI agent presents exactly the identity intended, keeps working through certificate rotation, and uses a certificate only where a certificate is the right tool at all.

Two ways it fails: no certificate, or the wrong one

In mutual TLS the server, after presenting its own certificate, sends a request for a client certificate. The client must answer with a certificate whose private key it holds, and the server then validates that certificate and decides whether to accept the connection, and often maps it to an identity. Almost every production problem with this exchange falls into one of two shapes.

The first is that no certificate is sent. The client may have no suitable certificate, automatic selection may be switched off, the only candidates may come from an issuer the server does not trust, or the program may simply never have been told which certificate to use. Depending on the server's settings, the connection then fails, or continues without client authentication, which is worse because it can look like success.

The second is that the wrong certificate is sent. A machine or user store often holds several certificates that would technically do: a device certificate, a user certificate, an old one not yet deleted, one issued for a different purpose. If the client picks by searching rather than by being told, it may pick any of them, and the server will either reject it or, more dangerously, accept it as a different identity. Both shapes have the same remedy, which the rest of this article develops: make selection explicit on the client and make acceptance explicit on the server.

How the client side chooses

A program that calls Schannel through the Security Support Provider Interface (SSPI) describes its credentials in an SCH_CREDENTIALS structure. Microsoft's reference notes that client applications often pass an empty certificate list and depend on Schannel to find an appropriate certificate. That automatic behaviour is controlled by flags: SCH_CRED_USE_DEFAULT_CREDS asks Schannel to supply a certificate chain for client authentication itself, while SCH_CRED_NO_DEFAULT_CREDS forbids it, and the ISC_REQ_USE_SUPPLIED_CREDS request flag tells Schannel not to supply credentials automatically during the handshake. When the server asks for a certificate and the supplied credentials contain none, or contain one whose issuer the server does not trust, the handshake call returns SEC_I_INCOMPLETE_CREDENTIALS, giving the program a chance to supply one.

If nothing suitable is found, Schannel logs warning event 36875 on the client: the remote server requested client authentication, no suitable client certificate could be found, and an anonymous connection will be attempted. Microsoft adds that the attempt might succeed or fail depending on the server's policy. That sentence is the reason to treat 36875 as a finding rather than noise.

In .NET, the defaults lean the other way. HttpClientHandler's ClientCertificateOptions property decides whether a certificate is picked automatically from the store or supplied by the caller, and its default is Manual. With SslStream, a client supplies its certificate through the ClientCertificates collection, a LocalCertificateSelectionCallback, or, from .NET 8, a ClientCertificateContext. Microsoft recommends the certificate context because building it constructs the certificate chain once, which is costly, and because it is the recommended way to send intermediate certificates: the alternative, adding intermediates to the machine or user store, affects every application on the system.

Selection is safest when the application names the certificate and Schannel is told not to search on its own.Who picks the certificateServerApplicationSchannelRequest client certoptional issuer hintName by thumbprintsupplied credentialsSearch storedefault credentialsSend certificatewith intermediatesNone found: 36875anonymous attemptautomaticexplicitcontextfirst matchno match
Selection is safest when the application names the certificate and Schannel is told not to search on its own.

What the server sends, and what it enforces

A server can include, with its certificate request, a list of the certificate authorities it trusts for client authentication. Microsoft documents that Schannel-based servers do not send this trusted issuer list by default, since Windows Server 2012 and Windows 8, because it exposes the server's trusted authorities to passive observers and enlarges the handshake. The registry value SendTrustedIssuerList set to 1 turns it on. The trade-off is real: without a list, Microsoft notes that Microsoft Edge shows the user every installed client certificate and that TLS clients in general may offer any available certificate; with a list, the client can narrow its choice to certificates that chain to a listed issuer.

When the list is sent, Schannel builds it from certificate stores in a defined order: a store configured for the application or site, then the local computer's Client Authentication Issuers store if it holds certificates, then the Trusted Root Certification Authorities store. The list has a maximum size of 16 KB; when trusting too many authorities pushes it past that, Schannel truncates it and logs event 36885. A small, deliberate Client Authentication Issuers store keeps the hint short and meaningful.

Sending a hint and enforcing a rule are different settings. How strictly the client's chain is judged is a machine-wide value, ClientAuthTrustMode, with three documented modes. Services on http.sys add per-binding controls through netsh http: clientcertnegotiation (disabled by default) decides whether the binding asks for a certificate during the handshake, and sslctlstorename names a local machine store holding the trust list for that binding. Schannel can also map an accepted certificate to a Windows account, using methods that include service-for-user mapping (enabled by default), user principal name mapping, one-to-one and many-to-one mapping.

What a Schannel server advertises to clients is separate from what it actually requires of their certificates.Hint versus ruleThe hint: what it sendsThe rule: what it enforcesSends: issuer listoff by defaultSends: from storesapp, issuers, rootscapped at 16 KBEnforces: trust modeClientAuthTrustModeEnforces: bindingnetsh per endpointvs
What a Schannel server advertises to clients is separate from what it actually requires of their certificates.
ClientAuthTrustMode values as documented by Microsoft for Schannel servers.
ValueModeClient certificate must
0 (default)Machine Trustbe issued by a certificate in the trusted issuers list
1Exclusive Root Trustchain to a root in the caller-specified store, and be issued by a listed issuer
2Exclusive CA Trustchain to an intermediate or root in the caller-specified store

The same decisions in ASP.NET Core and Kestrel

Many Windows services today are ASP.NET Core applications on the Kestrel web server, which uses the operating system's TLS on Windows. Microsoft's certificate authentication guidance shows Kestrel configured with ClientCertificateMode set to RequireCertificate, and an authentication handler whose defaults are worth knowing before production. AllowedCertificateTypes defaults to chained certificates only. ChainTrustValidationMode defaults to the system trust store; switching it to custom root trust uses a CustomTrustStore that, Microsoft stresses, must contain every issuing certificate in the chain. ValidateCertificateUse checks that the certificate carries the Client Authentication extended key usage, or none. RevocationMode defaults to an online check, which Microsoft warns can cause long delays while the certificate authority is contacted.

Two limits shape architecture. Microsoft is explicit that requiring a certificate only on certain paths is not possible, because the certificate exchange completes at the start of the connection, before any request is seen. And asking for a certificate later in a connection, through renegotiation, is discouraged: it is a security risk, HTTP/2 and HTTP/3 prohibit it, and TLS 1.3 replaced it with a narrower post-handshake request that carries the same buffering and protocol constraints. Design endpoints that need client certificates as their own host name or port. Finally, a server that validates client certificates may try to fetch missing issuers or revocation data from addresses named inside the certificate, which can expose it to slow or hostile servers; Microsoft notes that from .NET 11, SslStream no longer downloads issuer certificates this way by default when it validates client certificates as a server.

Seeing which identity actually connected

Mutual TLS has its own diagnostic signals, and they live on both sides. On the client, event 36875 says no suitable certificate was found and an anonymous attempt followed, and a program calling Schannel directly sees SEC_I_INCOMPLETE_CREDENTIALS. A TLS 1.3 server that wanted a certificate and received none may send alert 116, certificate_required, which RFC 8446 defines for exactly that case. On the server, event 36885 says the trusted issuer list was truncated, a frequent hidden reason why well-configured clients stop finding their certificate after someone adds more trusted roots.

The success side is just as useful. When Schannel's logging includes success events, event 36880 records each completed handshake, and in October 2026 inspection on Windows 11 its structured data included LocalCertSubjectName and RemoteCertSubjectName alongside the protocol and cipher suite. On a server, the remote subject is the client identity that connected. That turns the event log into an audit trail for mutual TLS: which client identity reached which service, when, and over what protocol, without adding code. For services that log in the application instead, the same rule applies: record the subject and thumbprint of the accepted client certificate on every connection.

Rotating certificates without an outage

Rotation fails when it is treated as a swap. It succeeds when it is treated as a period of overlap, during which both the old and the new certificate are acceptable, followed by a verified cut-over and a clean removal.

For a client certificate from the same issuer, issue the new certificate well before the old one expires, install it beside the old one with its private key protected, and change the client's configuration to the new thumbprint. Because a certificate context built once keeps the chain it was built with, the program must rebuild its context, which in practice means reloading configuration or restarting the service. Confirm in the server's logs that the new subject and thumbprint are arriving, then remove the old certificate. For a change of issuing authority, order matters more: make the server trust both issuers first, by adding the new authority to its client authentication trust, then move clients one group at a time, and only remove the old authority after no connection has used it for a full business cycle. For server certificates on http.sys, netsh http update sslcert replaces the certificate hash on an existing binding.

Key custody keeps rotation safe. Generate keys on the host that uses them, mark them non-exportable where the workload allows, and give read access to the private key only to the service's own identity, such as a group managed service account. Before cutting over, confirm the key is usable by that identity; Microsoft's troubleshooting guidance uses certutil -verifykeys to check that a certificate's private key is available.

Rotation is a loop with an overlap period, a verified cut-over and a removal step, repeated before every expiry.Overlap rotationIssue newbefore old expiresTrust bothserver firstSwitch clientsnew thumbprintVerify subjectserver logsRemove oldafter a cyclenext expiryoverlap period:old and new both accepted
Rotation is a loop with an overlap period, a verified cut-over and a removal step, repeated before every expiry.

When a token is the better identity

Every client certificate is a secret to issue, protect, rotate and eventually revoke. Microsoft's managed identities documentation states the alternative directly: managed identities eliminate the need for developers to manage these credentials, and applications use them to obtain Microsoft Entra tokens without handling any secret. The option is not limited to cloud virtual machines; Microsoft documents that applications on Azure Arc-enabled servers, which can sit in an on-premises data centre, can use a system-assigned managed identity to obtain an access token. Workload identity federation extends the idea to software that already has an identity from another provider, exchanging that provider's token for a Microsoft Entra token without a stored secret.

Mutual TLS still earns its place. It is the right tool when the server only understands certificates, as many appliances, older services and protocols do; when the identity must be bound to a device or host at the transport layer; or when policy requires the channel itself to be authenticated before any request is read. The two also combine well: mutual TLS can authenticate the connection between known hosts while a token carries the caller's authorization inside it. The decision is per endpoint, and the useful question is simple: if this server accepts Microsoft Entra tokens, what does a certificate add that a managed identity does not?

Moving right removes certificate custody and rotation from the workload; moving left is needed only where the server speaks certificates alone.From certificate to tokenworkload holds and rotates a certificateworkload holds no secretMutual TLS onlycertificate custodymTLS plus tokenchannel and callerManaged identityno stored secret
Moving right removes certificate custody and rotation from the workload; moving left is needed only where the server speaks certificates alone.

AI agents: one identity per agent, never any certificate

AI agents multiply the number of clients that need an identity, and they make attribution matter more, because an agent acts on someone's behalf and its tool calls need to be traceable to it. A single client certificate shared by every agent on a host erases that attribution: the server sees one identity for many actors. A better pattern is one identity per agent service, or per class of agent, with short lifetimes and keys that only that agent's service identity can read.

The selection rules for services apply with extra force to agents. An agent process should load its certificate by thumbprint from configuration and supply it explicitly, never accept whatever certificate a store search returns, and never fall back silently to an anonymous connection when 36875 says nothing suitable was found. Tool servers that accept agents over mutual TLS should record the client subject and thumbprint for every call, so that each action can be tied to the agent that made it. And where a tool server accepts Microsoft Entra tokens, giving each agent a managed identity removes certificate custody from the agent host entirely. For a practitioner, the decisions come down to who issues agent identities, how many agents share one, how rotation is automated, and which endpoints still require certificates at all.

⚠️
Attribution. If many agents share one client certificate, the server cannot tell which agent made which call, so give each agent service its own identity.

Key takeaways

  • Mutual TLS fails in two shapes, no certificate or the wrong certificate; explicit selection on the client and explicit acceptance on the server prevent both.
  • Schannel can search the store automatically; services should name their certificate by thumbprint and supply it, with intermediates, through a certificate context.
  • Schannel servers do not send a trusted issuer list by default; the list, when sent, is capped at 16 KB and truncation logs event 36885.
  • ClientAuthTrustMode, http.sys binding options and the ASP.NET Core handler settings decide what is actually enforced.
  • Rotate by overlap: trust both, switch clients, verify the new subject in logs, then remove the old.
  • Where a server accepts Microsoft Entra tokens, a managed identity removes certificate custody; give every AI agent service its own identity either way.

Glossary

Mutual TLS
A TLS connection in which the client also proves its identity with a certificate, not only the server.
Trusted issuer list
The list of certificate authorities a server may send to hint which client certificates it will accept.
Thumbprint
A hash of a certificate that identifies one specific certificate unambiguously.
Certificate context
In .NET, a prepared certificate plus its chain that a program builds once and reuses across connections.
ClientAuthTrustMode
A Schannel registry value that sets how strictly a server judges the chain of a client certificate.
Managed identity
A Microsoft Entra identity assigned to a workload so it can obtain tokens without storing any secret.
Workload identity federation
A way to exchange a token from another identity provider for a Microsoft Entra token without a stored secret.
Renegotiation
Changing TLS parameters partway through a connection, such as requesting a client certificate later; discouraged and prohibited in HTTP/2.

Further reading

  1. Transport Layer Security (TLS) registry settings (Microsoft Learn)
  2. Configure certificate authentication in ASP.NET Core (Microsoft Learn)
  3. TLS/SSL best practices for SslStream (Microsoft Learn)
  4. Managed identities for Azure resources (Microsoft Learn)