Glossary · Data

AccessLevel

In OPC UA, AccessLevel is a bit-mask attribute on a Variable declaring what the server allows on that node: current read, current write, history read, history write, and further bits for status and timestamp writes. UserAccessLevel is the same mask narrowed to what the currently authenticated user may do.

AccessLevel versus UserAccessLevel

AccessLevel is the node's capability, independent of who is connected. UserAccessLevel is the effective permission for the active session and is always a subset of it. A node can therefore show CurrentWrite in AccessLevel and no write bit in UserAccessLevel, which is exactly what an anonymous session sees on a properly locked-down server. A client that greys out controls should read UserAccessLevel, not AccessLevel; a client that describes the model should read AccessLevel.

The bits you will use

The low bits are CurrentRead with value 1, CurrentWrite with value 2, HistoryRead with value 4 and HistoryWrite with value 8, so a read-write historised tag reads as 7 or 15. Further bits cover semantic change, status write and timestamp write. AccessLevelEx extends the mask for newer features such as non-atomic read and write and write-full-array-only. Read the numeric value and test bits; do not compare against a whole-word constant.

Why a write still fails

AccessLevel is advisory in the sense that passing it is necessary but not sufficient. A write can clear the AccessLevel check and still fail: BadNotWritable when the server is enforcing something the mask does not describe, BadUserAccessDenied when Part 18 role permissions deny it, BadTypeMismatch on a Variant shape problem, or a driver-level rejection because the underlying PLC tag is read-only in the controller regardless of what the OPC UA layer advertises. Diagnose in that order.

The timestamp write bits

StatusWrite and TimestampWrite say whether a client may supply a StatusCode or a SourceTimestamp in the DataValue it writes. Most servers do not allow either. This is the reason a write that works when you send only the Value field fails when your SDK helpfully populates SourceTimestamp for you, and the resulting error is often an unhelpful BadWriteNotSupported.

Example

Reading AccessLevel and UserAccessLevel side by side

from asyncua import Client, ua

async with Client("opc.tcp://milo.digitalpetri.com:62541/milo") as client:
    node = client.get_node("ns=2;s=Dynamic/RandomDouble")
    al = await node.read_attribute(ua.AttributeIds.AccessLevel)
    ual = await node.read_attribute(ua.AttributeIds.UserAccessLevel)
    print("AccessLevel", al.Value.Value, "UserAccessLevel", ual.Value.Value)
    # 1 = CurrentRead, 2 = CurrentWrite, 4 = HistoryRead, 8 = HistoryWrite
The mistake people make: Trusting AccessLevel to predict whether a write will succeed. It describes the node, not your session or the device behind it, so a tag advertising CurrentWrite can still return BadUserAccessDenied for an anonymous user or BadNotWritable because the PLC owns that address.

Defined in: Part 3 - Address Space Model, Variable attributes; Part 8 - Data Access.

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 Server Acceptance Test Pack
A 40-check acceptance test you run against a vendor's server before commissioning sign-off. Weighted scoring, three hard gates, and a one-page verdict for the supplier meeting.
Get the free test pack →
Free, no course, no login