Troubleshooting WinCC OPC UA Error 0x80310000 BadNoCommunication

David Krause13 min read
OPC / OPC UASiemensTroubleshooting
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Problem Summary

Siemens WinCC installations that expose OPC UA servers and are polled by QuickOPC-based .NET services intermittently return OPC UA StatusCode 0x80310000 (BadNoCommunication) with the textual description "Server not responding to keep-alive requests". The failure manifests as a coordinated pattern across three layers:

  1. The OPC UA client (QuickOPC) logs BadNoCommunication and OpcLabs engine code 3201 ("OPC-UA client session is not available when connecting the client subscription").
  2. An in-process WinCC API that forwards data raises Cannot lock the OPC-UA client session because it is not available during WriteMultiple.
  3. A custom HTTP healthcheck endpoint returns 503 ServiceUnavailable with the body Connection to OPC UA Alarms & Conditions Server not established, while a remote WinCC instance polling that endpoint logs the same 503 in parallel.

When the failure clears, the same log shows OPC UA Server Connected twice and both the healthcheck and downstream consumers return to 200 OK. The pattern is reproducible but transient, which is the classic signature of a server-side or transport-layer problem rather than a client-side bug.

The QuickOPC client is reporting an accurate symptom; it is not the root cause. QuickOPC's job is to surface server problems so the upstream system can react. Treat the error as a server-side investigation, not a client rewrite.

Decoding OPC UA Status Code 0x80310000

OPC UA StatusCodes are 32-bit unsigned integers defined in the OPC UA specification. The numeric value 0x80310000 encodes both severity and semantic meaning. Per the OPC UA StatusCode table (defined in the OPC UA specification, Part 4, section 7.39 and Part 6, Annex A):

Field Value Meaning
Severity bits (31:30) 11 (0x80...) Bad — operation failed, cannot be used
Sub-code bits (29:16) 0x3100 Sub-code group
Info bits (15:0) 0x0000 No additional structured info
Symbolic name BadNoCommunication Communication with the server has been lost
Hex 0x80310000
Decimal 2151677952

The specification text for BadNoCommunication states that the server cannot be reached, the session has timed out, or the underlying connection has been closed without a clean CloseSession exchange. The accompanying QuickOPC message "Server not responding to keep-alive requests" specifically points at the subscription keep-alive timer, which is a transport-layer liveness probe defined in OPC UA Part 4.

Reference: OPC UA Specification Part 4 (Services) and Part 6 (Mappings).

OPC UA StatusCode Severity Classes Used in This Fault

Hex Code Name Origin in This Fault
0x00000000 Good Baseline when subscription is healthy
0x80310000 BadNoCommunication Logged 4x during the keep-alive failure window
0x80050000 BadServerNotConnected Implied by "OPC UA Server not connected" message
0x80220000 BadTimeout Possible alternate reading if keep-alive interval exceeded
0x80230000 BadShutdown Appears if the server was deliberately stopped
0x80060000 BadServerHalted Appears if WinCC OPC UA service crashed

The QuickOPC engine code OpcLabs.UAEngine=3201 is a vendor-specific OpcLabs diagnostic code, not an OPC UA StatusCode. It maps to "OPC-UA client session is not available when connecting the client subscription". Treat it as confirmation that the QuickOPC library observed the underlying BadNoCommunication and reacted by tearing down its session state.

System Architecture Analysis

The deployment under investigation has three distinct logical roles that share infrastructure. Drawing the data flow explicitly makes the failure correlation obvious:

WinCC Server (Source)OPC UA Server :4840Runtime data + Alarms ProblemserverC# / QuickOPC clientReads OPC UA, hosts API Downstream ServerHTTP consumerPolling /api/healthcheck Healthcheck EndpointGET /api/healthcheck200 OK / 503 Service Unavailable OPC UA HTTP Polled health Internal Server logs: OPC UA stack traces Problemserver logs: BadNoCommunication Downstream logs: HTTP 503

Important architectural insight from the source: the "problemserver" is itself a WinCC server. That means the QuickOPC client and the WinCC OPC UA server can run on the same physical or virtual host. This complicates isolation because a CPU, memory, or disk pressure event on that host can affect both ends of the OPC UA conversation simultaneously and look like a network problem.

Error Sequence Timeline

Reconstructing the log ordering of one fault window reveals a deterministic cascade:

Order Component Event Implication
1 Problemserver "OPC UA Server not connected" (2x) Initial channel / session drop detected
2 Problemserver WRN BadNoCommunication 0x80310000 (4x) Keep-alive timer expired N times
3 Problemserver ERR Cannot lock OPC-UA client session (WriteMultiple) Downstream writes attempted during outage
4 Problemserver WRN OpcLabs.UAEngine=3201 (2x) Subscription reconnect attempts failed
5 Problemserver "OPC UA Server not connected" (1x) Reconnect attempt confirmed failure
6 Healthcheck GET /api/healthcheck -> 503 (looping) All three state predicates returned false
7 Problemserver "OPC UA Server Connected" (2x) Session re-established, recovery
8 Healthcheck GET /api/healthcheck -> 200 OK State predicates true again

The fact that BadNoCommunication appears four times in a row before the client gives up is consistent with OPC UA keep-alive semantics: the client must miss k consecutive keep-alives (where k = publishingInterval / keepAliveCount) before tearing down the subscription.

Root Causes of BadNoCommunication

Based on the OPC UA specification and the symptom pattern, work through this list from most likely to least likely:

# Cause Diagnostic
1 WinCC OPC UA server CPU starvation or GC pause on the problemserver host (server runs locally) Task Manager / perfmon during outage window; check for managed memory pressure
2 Network path interruption (firewall idle-timeout, route flap, MTU black hole) Continuous ping + pathping during outage; check switch port counters
3 WinCC OPC UA server service crashed and was auto-restarted by the OS Event Viewer -> Application log -> filter by source "SIMATIC WinCC"
4 OPC UA server certificate expired or trust store out of sync WinCC OPC UA Configuration -> Certificates tab
5 Subscription timeout / keepAliveCount configured too aggressively for an intermittent path Compare WinCC server config vs QuickOPC client defaults
6 Anti-virus or backup software opens files exclusively on the WinCC project directory Sysinternals Process Monitor during outage
7 Clock drift between client and server beyond certificate validity window w32tm /query /status on both ends
8 Shared session: another consumer is exhausting the server's session limit WinCC server diagnostic counter: "Open Sessions"
When multiple OPC UA clients connect to the same WinCC server, the server itself sets a maximum session count. If the limit is reached, new sessions are rejected with BadTooManySessions (0x80BB0000), not BadNoCommunication. Therefore "several client sessions open in parallel" is unlikely to be the direct cause of this specific 0x80310000 pattern; it is a symptom to verify, not a hypothesis to chase.

Server-Side Diagnostics in WinCC

The WinCC OPC UA server is configured inside the WinCC project, not from a generic OPC UA management tool. Two paths cover both WinCC Classic and WinCC Unified:

WinCC V7 / Classic (SIMATIC WinCC Explorer)

  1. Open the WinCC project on the problemserver.
  2. In WinCC Explorer, right-click OPC UA Server and select Properties.
  3. Open the Runtime tab and verify: Server starts with WinCC Runtime is enabled and the endpoint URL is opc.tcp://<server>:4840.
  4. Open the Security tab and check the current server certificate's valid-from / valid-to dates.
  5. In the Windows Event Viewer, expand Applications and Services Logs -> SIMATIC WinCC and correlate the outage window with OPC UA Server start/stop events.

WinCC Unified (V16+)

  1. In TIA Portal, open the WinCC Unified device.
  2. Navigate to Properties -> OPC UA Server.
  3. Inspect Sessions (max sessions), Subscription settings (max subscriptions per session, publishing interval, keep-alive count), and Diagnostics logging level.
  4. Verify that Server diagnostics enabled is checked; this populates server-side counters available via the OPC UA diagnostic nodes.

Reference: Siemens Industry Online Support for the WinCC OPC UA configuration manuals specific to the installed version (WinCC V7.5 SP2, WinCC Unified V18, etc.).

Client-Side Hardening in QuickOPC

Even though the source is on the server side, the QuickOPC client can be tuned so the application survives a brief outage without flooding the log and without dropping writes.

Recommended QuickOPC parameter map

Parameter Default Recommended for intermittent links Effect
Session.Timeout 60000 ms 120000 ms Server keeps the session alive longer across short blips
Subscription.PublishingInterval 500 ms 1000 ms Lower CPU pressure on the server, slower detection
Subscription.KeepAliveCount 10 30 Miss 30 keep-alives (~30 s at 1 s) before tearing down
Subscription.LifetimeCount 100 300 Subscription lingers longer before server deletes it
Subscription.MinLifetime 10000 ms 30000 ms Client refreshes subscription less aggressively
Reconnection policy Implicit Explicit exponential backoff (1 s, 2 s, 4 s, max 30 s) Avoids reconnect storms during a server outage

QuickOPC usage example (C#)

using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.OperationModel;
using OpcLabs.EasyOpc.UA.Parameters;

var client = new EasyUAClient();

// Tune session and subscription parameters
var parameters = new UACreateSubscriptionParameters
{
    PublishingInterval = 1000,
    KeepAliveCount = 30,
    LifetimeCount = 300,
    MinLifetime = 30000
};

UAEndpointDescriptor endpoint = new UAEndpointDescriptor(
    "opc.tcp://problemserver:4840");

UADataChangeSubscriptionCallback handler = (sender, args) =>
{
    if (args.StatusCode.IsBad)
    {
        // Handle BadNoCommunication explicitly without retrying writes
        if (args.StatusCode.Code == 0x80310000)
        {
            GlobalFields.Logger.Warning(
                $"OPC UA keep-alive lost: {args.StatusCode}");
            return;
        }
    }
    // Forward value upstream
};

client.SubscribeDataChange(endpoint, "ns=2;s=Channel1\Device1\Tag1",
    parameters, handler);

Reference: OpcLabs QuickOPC product page and the EasyUAClient API documentation for property names applicable to the installed version (QuickOPC 2023.x and 2024.x).

Healthcheck Endpoint Dependencies

The C# controller method exposed in the source ties the healthcheck output to three predicates:

public HttpResponseMessage Get()
{
    if (SyncController.StateIO == false
        || GlobalFields.RefreshComplete == false
        || GlobalFields.TransmitGSDV != "true")
    {
        GlobalFields.Logger_Healthcheck.Warning(
            HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]
            + ": GET Request Healthcheck --> (503 ServiceUnavailable)");
        return Request.CreateResponse(
            HttpStatusCode.ServiceUnavailable,
            "Connection to OPC UA Alarms & Conditions Server not established");
    }
    else
    {
        GlobalFields.Logger_Healthcheck.Information(
            HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]
            + ": GET Request Healthcheck --> (200 OK)");
        return Request.CreateResponse(
            HttpStatusCode.OK,
            "Connection to OPC UA Alarms & Conditions Server OK");
    }
}

Recommendations for the healthcheck contract

  1. Distinguish "OPC UA not currently connected" from "API not initialized". Today the 503 conflates the three predicates; a downstream WinCC server cannot tell whether to retry or escalate.
  2. Include the last successful data update timestamp in the JSON body. A 503 with lastGoodValue: 2024-05-01T12:00:00Z is far more useful than 503 with a static string.
  3. Return Retry-After header on 503 so HTTP-aware probes back off.
  4. Move the healthcheck evaluation off the request thread. If the QuickOPC session state is checked synchronously, a blocked OPC UA call stalls the HTTP thread and can exhaust the thread pool.

Suggested improved healthcheck body

{
  "status": "degraded",
  "checks": {
    "opcUaSession": {
      "ok": false,
      "lastError": "0x80310000",
      "lastGood": "2024-05-01T11:58:14Z"
    },
    "refreshComplete": { "ok": true },
    "gsdvTransmit":   { "ok": true }
  },
  "nextRetryMs": 5000
}

Network and Wireshark Capture Procedure

If the server-side logs do not identify the cause, capture traffic between the QuickOPC client and the WinCC OPC UA server.

  1. Install Wireshark on the problemserver and on the WinCC server (or use a mirror port on the switch).
  2. Start a capture on the interface that carries the OPC UA traffic. Filter: tcp.port == 4840.
  3. Reproduce the fault window (or wait for the next intermittent failure).
  4. Save the capture and analyze:
    • Open the Conversations dialog. Look for the OPC UA TCP session. If the conversation shows a RST or FIN during the outage, the client or server tore down the socket.
    • Filter for OPC UA messages: opcua (if the dissector is loaded) or tcp.port == 4840 && tcp.len > 0.
    • Look for PublishRequest / PublishResponse sequences. The interval between PublishRequests corresponds to the negotiated PublishingInterval. Gaps longer than PublishingInterval * KeepAliveCount indicate a real server-side stall.
    • Look for ServiceFault messages in either direction. The fault contains the StatusCode returned for the failing service call.
  5. If encryption is enabled, the OPC UA payload is opaque. Switch the WinCC OPC UA server temporarily to None security policy and a self-signed certificate for diagnostic capture only, then revert.
Capturing production traffic with security disabled is acceptable only on an isolated network, for the duration of the diagnostic window. Restore the security policy before returning the system to service.

Step-by-Step Resolution Procedure

  1. Confirm the symptom class. Grep all QuickOPC logs for 0x80310000 and the OpcLabs engine code 3201 over a 7-day window. Tabulate hour-of-day and duration. Look for clustering that correlates with backups, antivirus scans, or scheduled jobs.
  2. Check WinCC server health during the window. On the problemserver, open Task Manager -> Performance and Resource Monitor. A CPU spike or memory pressure that coincides with the OPC UA outage points at host contention, not OPC UA itself.
  3. Read the WinCC OPC UA server logs. In WinCC Explorer, raise the OPC UA server diagnostic verbosity to Information or Verbose. Reproduce or wait for the fault. Look for stack traces, certificate validation failures, or session-limit messages.
  4. Inspect certificates. Open %ProgramData%\Siemens\Automation\OpcUa\PKI\ on the WinCC server and the QuickOPC client's trusted store. Any expired certificate or trust mismatch will close the channel silently.
  5. Capture network traffic. Follow the Wireshark procedure above. Compare the PublishRequest cadence before, during, and after the outage.
  6. Tune the client keep-alive. Adjust QuickOPC KeepAliveCount and LifetimeCount per the table above. This is a stability improvement, not a root-cause fix; do it as a hardening step, not a substitute for diagnosis.
  7. Add reconnect backoff. Wrap the QuickOPC subscription in an exponential-backoff reconnect policy. Without backoff, repeated reconnect attempts during a server outage will themselves contribute to the load that prevents recovery.
  8. Split the server role. If the OPC UA WinCC server runs on the same host as the QuickOPC client, consider moving the QuickOPC client to a separate host. This isolates the OPC UA server from client-side resource pressure and lets you determine which side is starving.
  9. Upgrade server-side OPC UA stack. Check the installed WinCC version against current Siemens updates. OPC UA stack bugs that cause intermittent hangs have been corrected in several WinCC V7 SP and Unified V updates.
  10. Update QuickOPC. Upgrade to the latest QuickOPC release. OpcLabs regularly improves reconnect handling, certificate management, and StatusCode classification.
  11. Improve the healthcheck contract. Implement the improved healthcheck body from the previous section. A descriptive payload eliminates the need for guesswork during the next outage.

Verification Checklist

Check Pass Criterion
No BadNoCommunication in 72-hour log window 0 occurrences
Healthcheck returns 200 OK for > 99% of probes Uptime > 99%
Wireshark: no TCP RST/FIN on OPC UA session during normal operation 0 unexpected resets
PublishRequest cadence matches PublishingInterval ± 10% Within tolerance
CPU on problemserver < 70% sustained Headroom remains
WinCC server certificate valid > 30 days Buffer remains
Clock skew between client and server < 30 seconds Within tolerance

Frequently Asked Questions

What does OPC UA StatusCode 0x80310000 actually mean?

It is the standard OPC UA BadNoCommunication status code. Severity = Bad (top two bits = 11), sub-code 0x03100000. The OPC UA specification defines it as: communication with the server has been lost, the session has timed out, or the connection was closed without a CloseSession exchange. In QuickOPC, it almost always surfaces as "Server not responding to keep-alive requests".

Is 0x80310000 a client bug or a server bug?

It is reported by the client but originates on the server or the network between them. The client has done its job: it detected missing keep-alive responses and tore down the subscription. Look first at the WinCC OPC UA server's health (CPU, memory, certificate), then at the network path, then at the QuickOPC library version.

Could multiple OPC UA client sessions be the cause?

Indirectly, if the cumulative load exceeds the server's session, subscription, or CPU limits. The WinCC OPC UA server rejects new sessions with BadTooManySessions (0x80BB0000), not with BadNoCommunication. So parallel sessions alone do not produce this code; only an overloaded server or a transport problem does.

Should I lower the keep-alive count to detect failures faster?

No. A lower keep-alive count makes the client tear down sessions more aggressively on transient blips, which makes the system less reliable. The recommended approach for intermittent networks is the opposite: raise KeepAliveCount to roughly 30 and PublishingInterval to 1000 ms, then add an explicit exponential-backoff reconnect policy.

Why does the healthcheck return 503 even though OPC UA recovers on its own?

The healthcheck is bound to three boolean predicates: StateIO, RefreshComplete, and TransmitGSDV == "true". During the outage at least one of these is false, so the endpoint returns 503. As soon as the predicates recover, the endpoint returns 200. The 503 is therefore a faithful indicator of state, but it is uninformative about cause. Replace the static response with the JSON body shown above to give downstream consumers actionable detail.

Where can I find the official definition of OPC UA StatusCodes?

OPC UA StatusCodes are defined in the OPC UA specification, Part 4 (Services), section 7.39 "StatusCodes", and Part 6 (Mappings), Annex A "StatusCodes". The OPC Foundation publishes the unified architecture specification at opcfoundation.org/developer-tools/specifications-unified-architecture. WinCC-specific configuration is documented in the Siemens Industry Online Support portal at support.industry.siemens.com.

Back to blog