Why OPC UA Rejects a Server You Can Ping
Client won't connect though ping and port 4840 are open? Usually an endpoint URL, hostname SAN or ApplicationUri mismatch. Reading the status codes.
You can ping the server. opc.tcp://opcua-prod-01:4840 answers on the port. The server process is up and every tag is configured. And the client still won't connect — the session dies somewhere between opening the socket and browsing the address space.
When that happens, stop looking at sampling intervals and subscriptions. The session never got that far. What failed is identity: the client compared the endpoint URL, the server certificate, and the ApplicationUri against what it expected, and one of them didn't line up. This is a certificate and naming problem wearing a networking costume.
The socket opens before the check runs
An OPC UA client does two things that people conflate. First it opens a TCP connection to the endpoint URL and calls GetEndpoints (OPC UA Part 4). That succeeds as long as the port is reachable — which is why ping and telnet fool you. Then it picks an endpoint and tries to open a SecureChannel, and that's where the certificate and URI checks happen. A healthy socket tells you nothing about whether the SecureChannel will survive.
GetEndpoints hands back a list of EndpointDescription records. Each one carries the endpoint URL, the server's ApplicationDescription (including its applicationUri), the raw server certificate, the securityPolicyUri, and the securityMode. Save that list. The single most common commissioning mistake is trusting the address typed into the client config screen instead of what the server actually advertises — and servers happily advertise opc.tcp://localhost:4840 or a bench laptop's hostname if nobody told them their real name.
What the status code is telling you
The client log usually names the fault precisely. Learn the three that matter:
BadCertificateHostNameInvalid— the host you connected to (say10.20.30.40) isn't listed in the server certificate's Subject Alternative Name. Per OPC UA Part 4, the endpoint host has to appear as adNSNameoriPAddressSAN entry. Connect by DNS to a cert that only has the IP, or vice versa, and you get this.BadCertificateUriInvalid— the certificate's ApplicationUri doesn't match theapplicationUriin the endpoint's ApplicationDescription. The ApplicationUri lives in the cert as auniformResourceIdentifierSAN entry, and the spec requires the two to be identical, character for character. A vendor firmware upgrade that regenerates the URI but reuses the old cert lands here.BadSecurityChecksFailed— the catch-all: chain doesn't validate, cert expired, or the issuing CA isn't in the client's trust list.
None of these are protocol bugs. They're the security layer doing exactly what IEC 62443 wants it to do — refusing to bind to an endpoint whose identity it can't confirm. The ApplicationUri check in particular exists so a client can't be tricked into talking to a look-alike server that grabbed the same IP.
The tell that separates identity from network
One question sorts most of these fast: does the failure change when you connect by DNS name versus raw IP? If IP works and DNS fails (or the reverse), the certificate SAN doesn't cover the route you're using. If both fail identically at the SecureChannel stage, look at the ApplicationUri or the trust store instead.
A second useful split: does anonymous browsing with SecurityPolicy#None work while Basic256Sha256 with Sign or SignAndEncrypt fails? If so, the transport is fine and you've narrowed it to certificate identity — the None endpoint skips the checks that the signed endpoint enforces.
Disabling certificate validation to "confirm the direction" is fine for five minutes on a bench. Leaving it off in production is not a fix; it's removing the thing that stops a mistyped or hostile endpoint from being trusted silently.
Where these actually come from, and what to do
| What went wrong | How you spot it | The fix |
|---|---|---|
| Server renamed after the cert was issued | SAN still shows the old hostname | Reissue the cert with the final hostname and ApplicationUri |
| Client uses IP, cert only has a DNS SAN | Compare client URL against the cert SAN list | Connect by DNS, or add an iPAddress SAN if policy allows it |
| ApplicationUri changed in a firmware upgrade | Diff the endpoint list's applicationUri against the cert's URI SAN | Realign server URI and cert, then re-trust on every client |
| Redundant pair sharing one certificate | Inspect primary and standby certs separately | Issue a cert that covers both hosts, or one per host |
| Retired cert still trusted | Trust store holds two certs for similar names | Delete the old one; record the active thumbprint |
Endpoint advertises localhost | GetEndpoints returns opc.tcp://localhost:4840 | Fix the server's bind/advertise hostname before any client rollout |
I don't fix any of these by dropping to Basic128Rsa15 or None. Those policies are deprecated for good reason, and reaching for them turns a fifteen-minute naming cleanup into a permanent audit finding.
DNS and NAT: decide before you generate the cert
OPC UA certificates are issued for names, not for every possible route to a box. So the order of operations matters: pin the DNS record first, then generate the certificate against that name, then point clients at the same URL the server advertises. Do it the other way around and you're reissuing certs every time someone discovers a new path in.
A few things I'd hold the line on:
- One canonical endpoint name per server. Mixing
opcua-prod-01.local, the short hostname, and a raw IP across different clients means the cert has to cover all three, and something always gets missed. - Don't put a load balancer or reverse proxy in front of OPC UA unless the server stack and cert plan explicitly account for it — the client validates the name it dialed, and a proxy usually isn't in the SAN.
- If NAT is unavoidable, write down whether clients hit the inside name, the outside name, or a translated IP. That one sentence saves the next engineer an afternoon.
- For a temporary service laptop, give it its own endpoint profile. Don't keep re-editing the production certificate to accommodate a bench machine that'll be gone next week.
Test the thing you'll actually run
Two failure patterns survive commissioning because nobody exercises them:
Restart the server after importing certificates and reconnect. Some stacks only load or re-bind certs on startup, so a client that connected happily right after the import fails the next morning when the service bounces.
And on a redundant pair, test the standby path, not just the active one. The classic miss is a beautifully validated primary and a standby carrying a copied certificate that still lists only the primary's hostname — invisible until the day you fail over, which is exactly the day you can't afford to debug it.