← Articles
OPC UA/7 min read/ views

Why an OPC UA Setpoint That Browses Writable Still Rejects the Operator

AccessLevel vs UserAccessLevel vs WriteMask: why a setpoint that browses writable returns BadUserAccessDenied, and testing with the production identity.

OPC UASCADAHMITagsTroubleshooting

Writable in the browse tool does not mean writable by the operator

A setpoint browses fine in UaExpert. The pencil icon is there, you type a value, it takes. Then the HMI goes live under the SCADA service account and the same node returns BadUserAccessDenied (0x801F0000) on every write. Nothing about the address space changed — the identity did.

OPC UA keeps four attributes here that read almost the same when a project is rushed, and they are not interchangeable. Per OPC UA Part 3, AccessLevel is a byte bitmask of what the node supports at all: CurrentRead is bit 0 (value 1), CurrentWrite is bit 1 (value 2), so a writable value node reads AccessLevel = 3. UserAccessLevel uses the exact same encoding but is filtered for your session — the browse tool logged in as an engineer sees 3, the restricted runtime account sees 1. That single-bit gap is the failure, and a browse tool run under the wrong login hides it completely.

WriteMask and UserWriteMask are a different thing entirely (more on that below), and neither one governs whether you can write the Value.

Do not approve a write path because a browse tool showed a pencil icon. The pencil reflects the browsing session's UserAccessLevel, not the runtime's. Test the same endpoint, security mode, certificate, user, and role the SCADA runtime will use — or you are testing the wrong permission set.

Record access attributes beside the tag mapping

For each operator-writeable item, keep a small access record. It does not need to be a large security document, but it should be close enough to the tag list that engineers can use it during checkout.

ItemWhat to recordWhy it helps
NodeId and BrowseNameExact source node used by the HMIPrevents writes to a similarly named engineering node
Data typeBoolean, Int16, Float, enum, structureAvoids rejected writes and bad setpoint formatting
AccessLevelServer-level read/write capabilityShows whether the node is intended to accept writes
UserAccessLevelRuntime account capabilityCatches role or certificate differences
Range and unitEngineering limits and unitPrevents valid protocol writes with unsafe values
Expected reject reasonLocal mode, interlock, locked recipe, bad qualityHelps the HMI show a useful message

The access record is especially useful when a vendor exposes both command nodes and feedback nodes. Pump101.StartCmd and Pump101.Running may be close together in the address space, but only one should be written.

Treat WriteMask as configuration access, not operator control

A common misunderstanding is to read WriteMask as "can write the process value." It doesn't. In OPC UA Part 3, WriteMask is a 32-bit map over which attributes of a node can be modified — DisplayName, Description, the AccessLevel attribute itself, and so on. The Value attribute has its own dedicated bit, but for a normal Variable the writability of the Value is governed by AccessLevel/UserAccessLevel bit 1 (CurrentWrite), not by WriteMask. So a node can show WriteMask = 0 and still accept value writes all day. Most SCADA clients should never need WriteMask set in production — if it is, someone can rename your tags at runtime.

For operator controls, focus on:

  • CurrentWrite in UserAccessLevel for the runtime session.
  • Data type and array shape.
  • engineering range checks.
  • server-side role and certificate rules.
  • PLC or equipment state that may reject the command after the OPC UA write request is accepted.

If an HMI needs to change metadata at runtime, treat it as a configuration management feature and audit it separately. Normal start, stop, reset, and setpoint operations should not require metadata writes.

Test with the production identity

Many write failures are identity failures disguised as tag problems. The engineering user can write in the OPC UA test client, but the SCADA service account cannot. Or the HMI works before a certificate replacement and fails afterward because the server maps the certificate to a different role.

During checkout, run a write test matrix:

  1. Connect with the SCADA runtime user, certificate, endpoint URL, and security policy.
  2. Read AccessLevel and UserAccessLevel for the target node.
  3. Write a safe test value or use a vendor-provided simulation command.
  4. Confirm feedback from the equipment, not only the OPC UA write result.
  5. Repeat with an unauthorized user and verify that the write is rejected.
  6. Review the server audit log for the accepted and rejected attempts.

For a setpoint, include low, normal, high, and out-of-range values. For a command bit, prove that the bit does not remain latched because the client lost connection after writing.

Show protocol rejection differently from process rejection

Operators need to know whether the HMI could not write the tag or whether the equipment rejected the request. Those are different faults. The status code returned by the Write service (OPC UA Part 4, §5.10.4) tells you which layer said no — so surface it, don't swallow it.

Status codeLikely layerUseful operator message
BadUserAccessDenied (0x801F0000)OPC UA user or roleWrite rejected: HMI account not permitted
BadNotWritable (0x803B0000)OPC UA node access (CurrentWrite clear)Write rejected: node is read-only
BadTypeMismatch (0x80730000)Client value formattingWrite rejected: value type mismatch
BadOutOfRange (0x803C0000)Server range validationWrite rejected: value out of range
Good but feedback does not changePLC or equipment logicCommand sent, no running feedback
Good, then reject code in a status tagProcess validationCommand rejected: local mode

Do not collapse all of these into Command failed. The top group (Bad* status codes) usually needs engineering or security configuration work. The Good-with-no-effect cases are often normal process behavior — local mode, an interlock — that the operator can resolve at the panel.

Common failure modes

The browse account is not the runtime account

An integrator browses with an administrator account and imports tags. The runtime service uses a restricted account. Read tags work, but all setpoints fail after deployment.

Field check: browse and write once from the actual runtime host using the actual runtime credentials.

A replacement server changes role mapping

After an OPC UA server upgrade, the endpoint and NodeIds look the same, but certificate-to-role mapping is reset. The HMI can connect and read, but writes return access denied.

Field check: include user and role mapping in the backup/restore checklist, not only certificates and endpoints.

The HMI writes the feedback node

A template is bound to the wrong node because the command and feedback names are similar. The write may fail cleanly, or worse, it may write a simulation or override node.

Field check: for every command, trace the NodeId back to the vendor interface document or PLC export.

Commissioning evidence to keep

Save enough evidence that the next engineer can tell what was actually tested:

  • endpoint URL, security policy, and message mode;
  • client certificate thumbprint or application URI;
  • runtime user or role used for the test;
  • target NodeId, data type, and engineering unit;
  • successful write value and resulting feedback;
  • rejected write test and returned status code;
  • HMI message shown to the operator.

The one test people skip is the negative one: log in as an account that should not be able to write, attempt the setpoint, and confirm you get BadUserAccessDenied and an audit entry. A write path that only ever proves the authorized case is half-tested — you have shown the door opens, not that it locks.