SEC_E_UNTRUSTED_ROOT (0x80090325) — fix when TLS cert chain breaks
Happens when Windows can't trust a server's root CA cert. Common after proxy inspection, broken PKI, or expired intermediates. Here's the real fix.
When does this error actually show up?
You're running a PowerShell script that makes an HTTPS call, or maybe a .NET app trying to talk to an API. The connection drops immediately with SEC_E_UNTRUSTED_ROOT (0x80090325). I've seen this most often on Windows 10 22H2 and Server 2022 boxes behind corporate proxies that do SSL inspection. The proxy replaces the server's certificate with its own, but the proxy's root CA isn't in the machine's Trusted Root store. Another common trigger: you manually added a self-signed root CA but missed an intermediate in the chain, or the root expired and Windows no longer trusts it.
What's actually happening here
TLS handshake fails at the point where Windows checks the root certificate against the Trusted Root Certification Authorities store. Schannel (the Windows TLS stack) walks the certificate chain from leaf up. If any CA in that chain — root or intermediate — isn't trusted, or if its validity period is in the past, you get this exact error. The text "issued by an authority that is not trusted" is literal: Windows doesn't have that root in its store, or the root is present but marked as untrusted (yes, you can mark a root as untrusted).
The trick is that this error can also fire if an intermediate CA certificate is missing from the machine, even if the root is trusted. The chain validation fails because it can't build a path from leaf to root.
Fix it — step by step
- Find out which root CA is causing the problem.
Open Event Viewer → Windows Logs → System. Filter by sourceSchannel. Look for event ID 36888 or 36887 with status code0x80090325. The log entry usually includes the server's hostname and the hash of the offending root. Write that hash down. - Check the certificate chain manually.
Usecertutilto dump the chain for the failing URL. Run this in an elevated command prompt:
If the command throws an error about the root not being trusted, certutil will tell you exactly which certificate hash is untrusted. Compare it with the hash from the event log.certutil -urlcache * delete certutil -verify -urlfetch https://your-failing-server.com - Inspect the current root store.
Opencertlm.msc(Local Machine certificate store) as Administrator. Expand Trusted Root Certification Authorities → Certificates. Look for the root CA from step 2. If it's missing, you need to add it. If it's present but has a red X or says "Not trusted for this purpose", right-click → Properties → check the Trusted Purposes list. - Add the missing root CA.
Get the root CA certificate file (.cer or .crt) from your IT team or export it from the server that hosts it. Import it with:
Or via the GUI: right-click Trusted Root Certification Authorities → All Tasks → Import. Do NOT import into Intermediate Certification Authorities by accident — that's a different store and won't fix this error.certutil -addstore -f Root path\to\root-ca.cer - If the root is already trusted but the error persists, check intermediates.
Look in the Intermediate Certification Authorities store for the intermediate CA that issued your server's leaf cert. If it's missing, Windows can't build the chain. Import the intermediate .cer file using:
The store namecertutil -addstore -f CA path\to\intermediate.cerCAis the magic one for intermediates. Don't useRoothere. - Clear the certificate cache and retry.
After adding certificates, flush the cache:
Then restart your app or browser. The second command forces a cache resync within 60 seconds. Remove that registry value later if you want (it's a debug switch).certutil -urlcache * delete certutil -setreg chain\ChainCacheResyncTime @60000 - Reboot if you're on a domain-joined machine.
Group Policy sometimes pushes certificate trust lists that override local changes. A reboot ensures the updated store is picked up by all services.
What to check if it still fails
If the error persists, don't start randomly importing certs. Check these three things first:
- Is the server's certificate itself expired? Run
openssl s_client -connect your-server.com:443(or use certutil). If the leaf cert is expired, no amount of root trust will fix it. - Is the root CA marked as untrusted by Group Policy? Run
gpresult /h gp.htmland look for certificate trust policies. Domain admins can push an untrusted list that blocks specific roots. You can't override that locally — you'd need a policy exception. - Are you behind a broken SSL inspection proxy? Some proxies strip the intermediate CA from the chain sent to the client. The server sends its leaf cert, the proxy sends its own leaf, but omits the intermediate. In that case, manually importing the missing intermediate into the machine store (step 5) is the only fix. If the proxy uses a self-signed root that changes daily, you're hosed until IT fixes the proxy config.
One more thing: if this is in a development context and you're dealing with a self-signed certificate from localhost, you can temporarily trust it by adding it to Trusted Root Certification Authorities, but know that's a security risk for production workloads. In staging, at least use a proper internal CA.
Was this solution helpful?