BadShutdown
BadServer state
BadShutdown means the operation was abandoned because an application is going down - usually the server, sometimes your own client. It is normally a planned event, not a fault. Read SecondsTillShutdown and ShutdownReason from Server_ServerStatus to tell an orderly restart apart from a crash, then reconnect with backoff.
What you actually see
Every outstanding request completes with the same code at once, the connection drops immediately afterwards, and the server is unreachable for a short, bounded period.
Why it happens
- The server is shutting down in an orderly wayA conformant server moves ServerState to Shutdown, publishes SecondsTillShutdown counting down and a ShutdownReason, then closes sessions. Clients that read those fields can drain work and fail over gracefully instead of discovering the outage at the socket.
- A service restart, deployment or container terminationA systemd restart, an installer, a Kubernetes pod eviction or a Docker redeploy all end in the same place. Under an orchestrator the shutdown grace period is often short, so the countdown you get may be a second or two rather than a useful warning.
- PLC program download or configuration activationControllers stop their OPC UA server when a program is downloaded or a configuration activated. Treat this as a scheduled session close, and re-resolve NamespaceArray on reconnect, because indices can shift with the new program.
- Your own client is shutting downDisposing the client, cancelling the task group or leaving the async context cancels in-flight requests with this code. It is the correct behaviour and should not raise an alarm, but code that logs every fault at error level will make an orderly stop look like an incident.
- The server chose to shut down after a fatal conditionOut-of-memory, an unrecoverable internal error, or a watchdog can end in a deliberate shutdown. The distinguishing evidence is ShutdownReason and the server log, not anything visible on the client.
How to fix it
In diagnostic order: work down, do not skip ahead.
- Read the shutdown fields while you still canSubscribe to or read Server_ServerStatus - State, SecondsTillShutdown and ShutdownReason. A client that watches these can stop issuing work, close cleanly, and start its reconnect timer from a known point rather than guessing.
- Separate planned from unplannedCorrelate with your change calendar, deployment pipeline and PLC download records. A shutdown that matches a planned activity needs no investigation; one that does not needs the server log.
- Mark your own shutdown as plannedSet a shutting-down flag before disposing the client and suppress reconnect logic and error-level logging while it is set. This removes the most common false alarm from this code entirely.
- Reconnect with bounded backoff and jitterA restarting server is at its most fragile as it comes up, because every client dials at once. Randomise the first retry across the fleet so the restart does not turn straight into a connect storm and BadServerTooBusy.
- Re-resolve namespaces and transfer subscriptions on returnAfter a restart, read NamespaceArray and map URIs to indices again before using any cached NodeId. Then create and activate the session and try TransferSubscriptions, handling GoodSubscriptionTransferred, before rebuilding monitored items.
Where it shows up, by tool and stack
| Tool / stack | What to do there |
|---|---|
| UA-.NETStandard (C#) | The base server maintains ServerStatus including SecondsTillShutdown, and the client stack surfaces the shutdown as a session fault. Handle it distinctly from a network loss so your metrics separate planned restarts from outages. |
| Docker | A container stop sends SIGTERM with a short grace period, so the countdown clients see is minimal. Also remember that a non-persistent pki volume regenerates the application certificate on restart, which turns a routine redeploy into a trust failure. |
| Kubernetes | Pod eviction and rolling updates produce this on a schedule. Give the server a realistic terminationGracePeriodSeconds and keep opc.tcp pinned to a stable per-pod endpoint rather than a round-robin Service. |
| Siemens S7-1500 | A full program download stops the server and closes all sessions. Expect it on every deployment, and expect the address space to come back with potentially different namespace indices. |
| node-opcua | The client emits connection_lost after the shutdown and enters its reconnection strategy. Configure maxRetry and delays so a fleet does not converge on the server the instant it returns. |
| OPC Publisher | Module restarts and server restarts both appear as reconnect activity and telemetry gaps. Watch reconnect counts around planned maintenance to confirm recovery actually completed for every endpoint. |
What it looks like in the log
BadShutdown: the operation was cancelled because the application is shutting down
Server_ServerStatus: state=Shutdown, secondsTillShutdown=5, shutdownReason=Scheduled maintenance
Client disposing: cancelling 2 outstanding requests (planned shutdown)
Confirm the fix
After the server returns, confirm ServerState is Running, that NamespaceArray was re-read and indices re-mapped, and that subscriptions were transferred or rebuilt with data flowing again.
Stop it happening again
Publish planned restarts to the teams that own the clients, keep shutdown grace periods long enough to be useful, standardise a reconnect helper with jitter and namespace re-resolution, and never alarm on a shutdown you scheduled.
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.