Status code · Connection

BadTcpSecureChannelUnknown

BadProtocol

BadTcpSecureChannelUnknown means the transport layer received a message whose SecureChannelId and TokenId it does not hold. It is the transport-level counterpart of BadSecureChannelIdInvalid and usually means the server restarted, the channel was closed, or a load balancer sent you to a different instance.

Defined behaviour: The SecureChannelId and TokenId are not currently in use - the transport layer received a message for a channel it does not have. (our description of the condition this code reports)

What you actually see

Messages are rejected at the framing layer immediately after what looked like a successful reconnect, or immediately after a server restart while the client still had a socket open.

Why it happens

  • Server restarted and the channel table is goneChannel and token identifiers are in-memory server state. After a restart the client's cached ids match nothing. If the client re-established only the socket and reused the old channel id, every message is refused here.
  • Message sent on a channel that was already closedQueued requests flushed after CloseSecureChannel, or a retry issued from a background thread after an error path closed the channel, arrive with an id the server has released.
  • Token no longer currentThe pair of channel id and token id must both be recognised. A message signed with a token that has been superseded and dropped is refused, which is closely related to BadSecureChannelTokenUnknown.
  • Requests landing on the wrong server instanceTwo servers behind one address, whether by load balancer, DNS round-robin or a Kubernetes Service with several replicas, each keep their own channel table. The client is correct and the infrastructure is wrong.
  • Framing confusion from a middleboxA proxy that buffers or splits the byte stream, or a TLS-terminating device in front of opc.tcp, can present the server with bytes it parses as a channel id that was never issued.

How to fix it

In diagnostic order: work down, do not skip ahead.

  1. Check for a server restartRead Server_ServerStatus_StartTime after reconnecting, and compare with when your channel was opened. A restart makes this expected; the follow-up question is whether the client discards cached channel state properly.
  2. Ensure a channel error clears all channel stateOn any channel-level error, drop the channel id, token id and derived keys, close the socket, and open a fresh channel. Never retry the failed request on the old identifiers.
  3. Prove you are reaching one server instanceConnect several times and compare ApplicationUri and the server certificate thumbprint. Differences from a single URL mean traffic is being spread across instances.
  4. Remove round-robin and TLS-terminating middleboxesopc.tcp needs a single stable peer. Use a StatefulSet with per-pod addressing in Kubernetes, or a plain DNAT with no reassembly, and never a layer-7 proxy in front of opc.tcp.
  5. Capture the framing if it persistsWith the Wireshark OPC UA dissector, read SecureChannelId and TokenId on each UASC message and compare with what the server issued in the OpenSecureChannel response.

Where it shows up, by tool and stack

Tool / stackWhat to do there
UA-.NETStandard (C#)The transport channel owns these identifiers. Recreate the channel object rather than trying to repair it; the SessionReconnectHandler does this for you.
open62541 (C)The UA_SecureChannel state is tracked separately from the session, so the client state callback tells you clearly that the failure is at channel level.
node-opcuaClientSecureChannelLayer will rebuild the channel on reconnection. This code appearing repeatedly points at duplicate channels or a load-balanced endpoint rather than at the stack.
KubernetesA Service with multiple replicas is the classic cause. Give each server pod its own stable endpoint and address it directly.
Wireshark OPC UA dissectorShows the OPN response carrying the issued channel and token ids, then every MSG that references them - which makes a wrong-instance problem obvious within a few frames.

What it looks like in the log

BadTcpSecureChannelUnknown - the SecureChannelId and TokenId are not currently in use
Discarding message for unknown channel 33/token 2 from 10.20.3.15
OpenSecureChannel issued channelId=34 tokenId=1 after reconnect

Confirm the fix

Reconnect and confirm a new OpenSecureChannel with fresh identifiers, then sustain traffic with no transport-level rejections across at least one token renewal.

Stop it happening again

Treat secure channel state as disposable in client code, pin OPC UA endpoints to a single server instance, and keep layer-7 proxies and round-robin load balancers off opc.tcp entirely.

Stuck on more than one of these? The troubleshooting clinic works through broken configurations end to end, on camera.

Troubleshooting clinic →

Last verified 7 September 2026 against OPC UA 1.05.07. OPC UA Connect is an educational resource and is not affiliated with the OPC Foundation.

Free download
OPC UA Status Code Diagnostic Tree
A 15-page diagnostic reference grouping every normative status code by what actually went wrong: with the first action for each, and the four questions that resolve most faults before you read a single code.
Get the free diagnostic tree →
Free, no course, no login