C · recipe

Connect to an OPC UA server in C

Create a client, apply the default configuration, then connect. open62541 returns a UA_StatusCode from everything: check it every time, because there are no exceptions to fall back on. Always delete the client to free its memory.

Stackopen62541
Version1.5.8

The code

#include <open62541/client_config_default.h>
#include <open62541/client_highlevel.h>
#include <open62541/plugin/log_stdout.h>
#include <stdio.h>

int main(void) {
    UA_Client *client = UA_Client_new();
    UA_ClientConfig_setDefault(UA_Client_getConfig(client));

    UA_StatusCode rc = UA_Client_connect(client, "opc.tcp://opcua.umati.app:4840");
    if (rc != UA_STATUSCODE_GOOD) {
        printf("connect failed: %s\n", UA_StatusCode_name(rc));
        UA_Client_delete(client);
        return 1;
    }
    printf("connected\n");

    /* read the namespace array: tells you what the server implements */
    UA_Variant nsArray;
    UA_Variant_init(&nsArray);
    rc = UA_Client_readValueAttribute(client,
            UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY), &nsArray);
    if (rc == UA_STATUSCODE_GOOD && nsArray.type == &UA_TYPES[UA_TYPES_STRING]) {
        UA_String *uris = (UA_String *)nsArray.data;
        for (size_t i = 0; i < nsArray.arrayLength; i++)
            printf("  ns=%zu  %.*s\n", i, (int)uris[i].length, uris[i].data);
    }
    UA_Variant_clear(&nsArray);

    UA_Client_disconnect(client);
    UA_Client_delete(client);
    return 0;
}

/* build:
   gcc client.c -lopen62541 -o client
   or with the amalgamation:
   gcc client.c open62541.c -lmbedtls -lmbedx509 -lmbedcrypto -o client
*/

What it prints

connected
  ns=0  http://opcfoundation.org/UA/
  ns=1  urn:umati:sample-server
  ns=2  http://opcfoundation.org/UA/DI/
  ns=3  http://opcfoundation.org/UA/Machinery/

Notes

  • Every call returns a UA_StatusCode. Check it. There is no exception mechanism, and ignoring a return value here produces the memory bugs that give C a bad name.
  • Every UA_Variant you initialise must be cleared with UA_Variant_clear, or you leak on every read.
  • The single-file amalgamation is the practical way to vendor this into an existing embedded build without adopting its build system.
  • Without mbedTLS or OpenSSL compiled in you get security policy None only, and no amount of configuration will change that.
  • The Query service set and HTTPS are not implemented. Design around that rather than discovering it late.

What breaks first

The connection fails immediately with no useful message BadConnectionRejected
Check TCP reachability to port 4840 first, then that the endpoint path is right. UA_StatusCode_name turns the numeric code into something you can search for.

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 Troubleshooting & Integration Checklist
The field-tested checklist engineers use to diagnose certificates, ports and namespace problems fast, plus a Python (asyncua) client template.
Get the free checklist →
Free, no course, no login