BadConnectionClosed
BadNetwork drop
BadConnectionClosed means the transport connection carrying your requests was closed - by the peer, by the network, or by a middlebox. The secure channel and any in-flight requests die with it. Reconnect the channel, re-bind or recreate the session, and transfer subscriptions rather than rebuilding them.
What you actually see
In-flight requests, especially long-polled Publish calls, all complete with the same error at the same instant, and the client's state goes to reconnecting.
Why it happens
- Physical or link-layer interruptionA cable, a switch reboot, a wireless roam, a spanning-tree reconvergence or a VPN renegotiation. The client sees a reset or an unanswered send. This is the plain and most common reason and it is what reconnect logic exists for.
- Idle timeout on a firewall or NAT deviceStateful devices expire idle TCP flows. An OPC UA client that keeps a Publish outstanding is not idle at the application level but may still be idle on the wire for long stretches if nothing changes, so the flow gets reaped.
- The server closed it on purposeShutdown, a session or channel abort after a protocol error, or a resource-pressure decision. Reverse connect also closes the channel after a client fetches endpoints, which is expected behaviour and not a fault.
- Message size or decoding failure handled by abortingRather than returning a per-request fault, servers often abort the connection on an oversized or undecodable message. Look for BadTcpMessageTooLarge, BadEncodingLimitsExceeded or a decoding error in the server log just before the close.
- Client process or host disruptionThe client host suspended, the process was paused by a long garbage-collection or a blocked event loop past the server's tolerance, or a container was rescheduled. From the log it looks like a network fault.
How to fix it
In diagnostic order: work down, do not skip ahead.
- Correlate with network and server eventsLine up the timestamp against switch logs, VPN events, server restarts and container events. A close that coincides with an infrastructure event needs no OPC UA investigation.
- Read the server log for a deliberate abortIf the server aborted the connection because of a protocol, size or security problem, only its log states why. Rule this in or out before tuning timers.
- Measure the idle interval before the closeIf closures happen after a consistent quiet period - fifteen minutes, an hour - you are looking at a middlebox idle timer. Enable TCP keep-alive on the client socket or shorten the OPC UA keep-alive so the flow is never idle that long.
- Reconnect through the layers in orderNew socket, new secure channel, re-bind or recreate the session, then TransferSubscriptions handling GoodSubscriptionTransferred. Only recreate monitored items if the transfer is refused.
- Add bounded backoff with jitterAn immediate tight retry loop after a close turns one outage into a connect storm and produces BadServerTooBusy and orphaned sessions. Bound the backoff and randomise it across clients.
Where it shows up, by tool and stack
| Tool / stack | What to do there |
|---|---|
| UA-.NETStandard (C#) | SessionReconnectHandler covers this case; the channel and session decoupling means the session often survives. Log reconnect counts as a health metric, because silent reconnects hide a deteriorating network. |
| node-opcua | The client emits connection_lost then start_reconnection and after_reconnection. Configure connectionStrategy with maxRetry, initialDelay and maxDelay rather than writing a retry loop. |
| asyncua (Python) | Connection loss surfaces as an exception from the pending request and through the client's watchdog. Use Client with a reconnect loop around connect, and re-resolve NodeIds after reconnect if the server may have restarted. |
| open62541 (C) | The state callback distinguishes the connection, channel and session layers, which is the fastest way to tell an idle-timeout close from a session timeout. |
| Ignition | The device connection shows Faulted then Connecting. Repeated short outages appear in tag history as gaps; the gateway log records the reconnect cadence you need for diagnosis. |
| Wireshark OPC UA dissector | Shows whether the close was a graceful CLO, an ERR frame carrying a status code, or a bare TCP RST with no OPC UA content - three quite different diagnoses. |
What it looks like in the log
BadConnectionClosed - socket closed while waiting for Publish response
Connection to opc.tcp://plc01:4840 lost (recv returned 0); scheduling reconnect in 2000 ms
Server aborted connection after BadTcpMessageTooLarge on request 118
Confirm the fix
Run for a full shift and count closures. Correlate any remaining ones with recorded network events; a steady cadence with no matching event means a timer somewhere is still shorter than your keep-alive.
Stop it happening again
Keep the flow non-idle with a keep-alive shorter than every idle timer in the path, standardise a reconnect helper with backoff and subscription transfer, and monitor reconnect rate as a leading indicator.
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.