---
title: HiveMQ Edge 2026.15 is Released
description: The HiveMQ team is pleased to announce the availability of HiveMQ Edge 2026.15.
date: 2026-10-23
author: HiveMQ Team
tags:
  - HiveMQ Edge
source: https://www.hivemq.com/changelog/hivemq-edge-2026-15-released
---

# HiveMQ Edge 2026.15 is Released

## What's New in HiveMQ Edge 2026.15

HiveMQ Edge 2026.15 lets MQTT clients call methods on OPC UA devices and receive the results as MQTT messages. The Docker images no longer trust the compromised eMudhra root CA. Method calls and writes now accept OPC UA structures and enumerations. The release also fixes OPC UA tag browsing on servers with strict request limits and adds struct members, array elements, and properties to browse results. OPC UA node ids can now name their namespace by URI. The Workspace gets a new Reload button.

## OPC UA Method Calls

### What It Is

HiveMQ Edge can now **call a method on an OPC UA device from an MQTT message** and publish the result back as an MQTT message. A new OPC UA tag kind, `METHOD`, sits beside `VALUE`, `CONDITION`, `REFRESH`, and `EVENT_SUBSCRIPTION`.

Until now, the OPC UA adapter read variables and wrote values. A manufacturing execution system (MES) or a supervisory control and data acquisition (SCADA) system had no way to *command* a machine through Edge. Typical commands start a batch, acknowledge an alarm, or change a recipe.

### How It Works

**A tag names the object, and the request names the method.** One boiler with four methods is one tag with one southbound topic and one northbound topic, not four of each. You do not list the methods. Edge reads them from the device when it verifies the tag.

```xml
<tag>
<name>boiler1</name>
<definition>
<node>ns=2;s=Boiler1</node>
<kind>METHOD</kind>
</definition>
</tag>
```

To call a method, publish a request to the tag's topic. The request names the method in `methodName` and carries the arguments in `value`, keyed by the names that the device declares:

```json
{ "methodName": "Start", "value": { "setpoint": 180, "ramp": "slow" } }
```

Edge publishes the response as its own message:

```json
{ "responseMethodName": "Start", "value": { "started": true, "actualSetpoint": 178 } }
```

**A failure has the same shape with one field added.** If `errorCode` is present, the call failed. The `errorCode` field carries the OPC UA status code by name, such as `Bad_NotExecutable`. If the device returns detail, `statusInfo` carries the detail. There is no success flag to check, and nothing else answers the question.

**Several calls can be outstanding on one topic.** A request can carry a `correlationData` token, and the response carries the token back. The token travels as a payload field or as the MQTT 5 `Correlation Data` property. A request can also name its own reply address in `responseTopic` or in the MQTT 5 `Response Topic` property. If a request carries either value both as a property and as a payload field, the two must agree. Otherwise Edge refuses the request and does not call the device. If three systems call the same boiler, each can name its own reply address and receive only its own responses.

**Edge generates a schema for each object** from the arguments that the device declares. Validation catches a misspelled argument name and most wrong types before Edge contacts the device. Edge checks the rest, such as an enumeration value, when it converts the argument, and publishes a response with an `errorCode`. Either way, the caller does not receive an opaque device error.

### How It Helps

- **Machine control, not only observation.** An MES drives equipment through Edge directly. The plant's OPC UA server no longer has to drive the MES.
- **One tag per object.** A new method on the device needs no configuration change in Edge; Edge reads it at its next connection to the device.
- **Responses that find their caller.** With correlation tokens and per-request reply addresses, several independent consumers can share one method tag.
- **Early error detection.** Edge refuses a malformed request before it reaches the device, keeps its payload on a quarantine topic, and logs what was wrong. A request for a method that the object does not have gets a response that says so. The device does not execute anything unintended.
- **Full support for MQTT 3 and MQTT 5.** Every field has a payload form, so an MQTT 3 caller loses nothing. MQTT 5 callers can use the native properties instead.

## Security: The Docker Images No Longer Trust the Compromised eMudhra Root CA

### What It Is

The private keys of eight eMudhra intermediate CAs have been disclosed. Each intermediate chains to the root `emSign ECC Root CA - G3` and is also cross-signed by Sectigo's root `AAA Certificate Services`. A Java runtime that trusts either root accepts forged TLS certificates for any host name. Up to 2026.14, the HiveMQ Edge Docker images trusted `emSign ECC Root CA - G3` in the JVM trust store.

### How It Works

The 2026.15 Docker images are built on a patched Eclipse Temurin base image without `emSign ECC Root CA - G3`; the Temurin trust store does not contain `AAA Certificate Services`. This covers every outbound TLS connection Edge makes from the JVM: MQTT bridges to remote brokers, the HTTP adapter, Data Intelligence connectivity and usage tracking. It also covers one inbound path: an MQTT TLS listener with client authentication and no trust store of its own checks client certificates against the JVM trust store. Up to 2026.14 such a listener accepted a client certificate that chains to `emSign ECC Root CA - G3`; in 2026.15 it refuses it. The other emSign roots, including `emSign Root CA - G1`, stay trusted.

**Zip distribution.** The zip runs on your own Java runtime. Remove both roots from that runtime's trust store until your JDK vendor ships a fix (some JDKs, for example Azul Zulu 21, ship both). Run this with the `keytool` of the Java runtime that runs Edge, as a user that can write its `cacerts` (replace `changeit` if you changed the trust-store password), then restart Edge:

```bash
for fp in 86:A1:EC:BA:08:9C D7:A7:A0:FB:5D:7E; do
  alias=$(keytool -J-Duser.language=en -J-Duser.country=US -list -v -cacerts -storepass changeit | awk -v fp="SHA256: $fp" '/^Alias name: /{a=substr($0,13)} index($0,fp){print a}')
  if [ -n "$alias" ]; then keytool -delete -cacerts -storepass changeit -noprompt -alias "$alias"; fi
done
```

To check: `keytool -list -cacerts -storepass changeit | grep -cE '86:A1:EC:BA:08:9C|D7:A7:A0:FB:5D:7E'` prints `0`.

### How It Helps

An attacker in the network path can no longer impersonate a remote broker or HTTP endpoint to Edge with a certificate issued under the compromised CAs, and a client can no longer authenticate to such an MQTT listener with one.

## Upgrade Notes

Every value that Edge sends to an OPC UA device, whether a tag write, a method argument, or an alarm acknowledgement, is now checked and converted by the same rules. Check the following before upgrading.

**Trusted root CAs (Docker images)**

- **The 2026.15 Docker images trust 117 root CAs instead of 144.** Besides the compromised eMudhra root, the new base image no longer contains 27 roots that 2026.14 trusted, among them DigiCert Global Root CA, DigiCert Assured ID Root CA, DigiCert High Assurance EV Root CA, COMODO Certification Authority, QuoVadis Root CA 2 and 3, GTS Root R2, and several Entrust, AffirmTrust, and Trustwave roots. A bridge, an HTTP adapter, or any other TLS connection whose server certificate chains only to one of them fails after the upgrade. Check the certificate chains of your remote brokers and endpoints before upgrading. To keep such a connection, add its root to the JVM trust store in an image built on `hivemq/hivemq-edge`.

**Published values**

- **An enumeration field inside a structure** is published as `{"name": "Running", "value": 2}`. Earlier releases published it as text, `"DynamicEnumType[...]"`. This applies to every server.
- **OPC UA standard structures are published as JSON objects with their definition's field names**, also on a server that does not describe OPC UA's own structures (many PLCs do not). On such a server, earlier releases published two of them with lower-case field names: `LocalTime` on alarm and condition events, and `EngineeringUnits` on limit alarms. They published every other standard structure as text, for example `Range{low=1.5, high=9.0}` instead of `{"Low": 1.5, "High": 9.0}`. If Edge cannot read the server's type hierarchy, it still publishes such a structure as text. Update any consumer that reads those forms.

**Writes that are now refused.** Each was sent to the device as a different value before:

- A GUID, or a node id with a `g=` identifier, written short. Write all 8-4-4-4-12 hex digits.
- A status code written as a negative number. Write the unsigned code: Bad is `2147483648`.
- An unknown field in a structure or a qualified name.
- A Float beyond the Float range, which was sent as infinity before.
- A negative UInt64.
- A whole number of 2^53 or more to an Int64 or UInt64, which the JavaScript transform has already rounded on its way in.
- `null` for a type that has no null value: a number, a Boolean, a GUID, a DateTime, an enumeration, or a structure. Also `null` for an array of any type: send `[]` instead, which OPC UA treats as the same value. A device can still refuse `[]` for an array of fixed length. Where no schema check applied, earlier releases treated `null` as an absent value.

**Writes that are now accepted, or kept more exactly:**

- A whole number to a Float or Double that does not fit exactly, or lies beyond the Int32 range: rounded to the nearest Float or Double, like any decimal.
- A DateTime with sub-millisecond digits: sent at OPC UA's 100 ns resolution instead of cut to milliseconds.
- A multi-dimensional array to a matrix variable.
- A status code as its unsigned code, the form Edge publishes.
- A structure that leaves out optional fields at its end. A field left out before a later one is still refused.
- A node id value by namespace URI, `nsu=<uri>;s=…`.
- An Acknowledge or Confirm with `"comment": {}`, which leaves the existing comment alone.
- `null` for a String, ByteString, XmlElement, NodeId, ExpandedNodeId, QualifiedName, or LocalizedText, also as an element of an array: Edge sends that type's null value. Earlier releases refused it at the schema check. A server that checks types can refuse a `null` String sent on its own, as a Siemens S7-1500 does, because Edge sends it without a type.

**Known issue:** a write to a variable of the `Image` type (and its PNG, GIF, JPG, and BMP subtypes) is refused in this release. Earlier releases wrote it as a byte string. A fix is planned.

**Downgrading**

- Edge 2026.14 and earlier cannot read a southbound mapping with method calls turned on. Before downgrading, turn method calls off on those mappings or remove the mappings.

## Additional Improvements

### Bug Fixes

- **Fixed OPC UA tag browsing on servers with strict request limits**: Tag browsing failed with HTTP 500 on servers that limit the number of nodes per request, such as the WAGO PFC200. Tag browsing now sizes its requests to the limits each server advertises, and retries with smaller requests when a server refuses one.
- **Fixed missing struct members, array elements, and properties in OPC UA tag browsing**: Browse results now include variables nested under other variables, for example struct members and array elements in Siemens S7-1500 data blocks. A browse can therefore return considerably more nodes than before; in our tests, two to three times as many on an S7-1500.
- **Fixed unstable default tag names**: Nodes that share a browse path now get the same generated default tag names on every browse.
- **Fixed JSON browse exports that looked complete after a failure**: If a JSON export fails partway through, the document is now left unterminated and fails to parse, instead of looking complete with rows missing.
- **Fixed OPC UA data types missing when a server refuses part of a request**: When Edge reads a server's data types, the server can refuse single entries of a request, for example when it runs out of continuation points. Edge treated such an entry as a type without subtypes and kept the incomplete list without an error, so tag browsing, write schemas, and writes for tags of a missing type lacked the type or failed. Edge now requests each refused entry again on its own. If the server still refuses one for lack of continuation points or operations, Edge does not keep the incomplete list and builds it again at the next health check. On servers that report no limit on operations per request, Edge now sends at most 100 per request.
- **Fixed false validation errors on empty optional tag fields**: The tag editor flagged optional fields left empty as invalid (for example `'Condition node ID' must be string`) and would not save the tag. This affected OPC UA, HTTP, and EtherNet/IP CIP tags. Empty optional fields now pass validation, and the tag saves normally.
- **Fixed memory growth and missing reconnects while an S7 or ADS PLC is unreachable**: While an S7 PLC was unreachable, the PLC4X driver retried about once a second and kept the network resources of every attempt, so Edge's memory grew for as long as the outage lasted (43 MB per hour for one adapter with two tags, measured) until the process ran out of memory. An S7 or ADS adapter that started while its PLC was down never connected afterwards. Edge now closes every connection attempt that fails or times out, which releases what the driver held, and the adapter reconnects on its own once the PLC is back. A failed attempt counts as a polling error, as for every polling adapter: with the default Max. Polling Errors of 10 the adapter stops after about 3.5 minutes of outage, so set it to -1 where PLCs are powered off for long periods. While an attempt runs the adapter shows the status CONNECTING, and CONNECTED only once the PLC has answered.
- **Fixed S7 and ADS adapters ignoring a changed host**: Edge restarts an adapter only when its configuration has changed, and for S7 and ADS adapters it did not consider the host when deciding that. An edit that changed only the host, through the REST API or `config.xml`, was saved, but the adapter was not restarted and kept polling the previous PLC, with no warning. This affected every release since 2025.5. If you changed the host of an S7 or ADS adapter and nothing else, check that the adapter is connected to the intended PLC; restarting Edge applies the stored configuration. Edge now restarts the adapter whenever the host changes.

### Improvements

- **Added structure and enumeration arguments to OPC UA method calls and writes**: An OPC UA method can now take a structure or an enumeration as an argument, for example `SetRecipe(recipe: RecipeType)` or `SetMode(mode: MachineMode)`. You send a structure as a JSON object with its field names, in the form Edge publishes it, and an enumeration as its number (`2`), its name (`"Running"`), or the object Edge publishes (`{"name": "Running", "value": 2}`). Edge reads the structure's definition from the server, so the request schema lists its fields, and a missing, misspelled, or mistyped field is refused with its path, for example `steps[1].temperature`. A structure or enumeration that Edge publishes is a valid argument as it stands, unless the structure has a field of an abstract type, such as `BaseDataType`, or a union field. The Upgrade Notes list the values whose handling changes.
- **Added a Reload button to the Workspace**: The Workspace canvas keeps its own copy of your adapters, bridges, combiners, and mappings in the browser, so your layout survives a page reload. Until now, that copy only grew. An object removed elsewhere, for example by another user, a REST call, or an edit to `config.xml`, stayed on the canvas. A click on such an object failed with a confusing error. The new **Reload workspace** button next to the zoom controls fetches everything from Edge again and updates the canvas. Your positions and groups stay as they are, and a failed or partial fetch changes nothing. A second option, which is deliberately harder to click, clears all local data and starts over. Before, the only way to reset the canvas was to delete a storage key in the browser's developer tools.
- **Added OPC UA node ids by namespace URI**: Wherever you write an OPC UA node id, you can now name its namespace by URI (`nsu=http://vendor.example/Boiler;s=Boiler1`) as well as by index (`ns=2;s=Boiler1`). This covers a tag's node, notifier, source and condition node, a browse root, a method name, and NodeId values that you write to the device or pass to a method. A namespace index is a position in the server's own table, and a server may renumber that table, which silently points a tag configured by index at a different node; a URI names the namespace itself. Edge resolves the URI each time it connects. If the server does not publish that namespace, Edge does not use the tag and reports an event naming the URI. It checks again on every connection; the adapter's other tags are unaffected. Existing configurations that use the index form behave as before, with one exception: a GUID identifier (`g=`) must now be written in full, as 8-4-4-4-12 hexadecimal digits. Earlier releases silently filled a shortened GUID with leading zeros, which can just as easily reach a different node. If a tag stops subscribing after the upgrade, write its GUID out in full.
- **Smaller JSON browse exports**: JSON exports from tag browsing are no longer indented, which makes them about a fifth smaller for the same nodes.
- **Added per-client limits to the MQTT listener**: The MQTT listener now limits how much memory a single client can make Edge hold. A SUBSCRIBE or UNSUBSCRIBE carries at most 10,000 topic filters (`max-topic-filters-per-packet`). Inbound QoS 2 messages awaiting PUBREL are limited to 1,000 per client and 100,000 per Edge (`max-incoming-qos2-flows-per-client`, `max-incoming-qos2-flows`), and their state now ends with the session. A client over a limit is refused with reason code 0x97 (MQTT 5) or disconnected (MQTT 3). Edge writes the three settings to `config.xml` only when they are set; remove any you set from `<restrictions>` before downgrading to 2026.14 or earlier.
- **Security:** Bouncy Castle updated to 1.86, Jackson to 2.22.3 (Jackson 3 to 3.2.3), and FreeMarker to 2.3.35. The updates resolve known vulnerabilities in these libraries, the most severe of them rated high.
- **Data Intelligence agent updated to 3.4.3.**
- **Dependency updates** including Eclipse Milo 1.1.8, Logback 1.6.4, and SLF4J 2.0.20.

## Get Started Today

Use the download link to get HiveMQ Edge 2026.15, or find us on GitHub and Docker:

Get started by running

```bash
docker run --name hivemq-edge --pull=always -d -p 1883:1883 -p 8080:8080 hivemq/hivemq-edge
```

Or clone our repository

```bash
git clone git@github.com:hivemq/hivemq-edge.git
```

You may also try out our Helm Chart

```bash
helm repo add hivemq https://hivemq.github.io/helm-charts && helm repo update
```

\


[Get HiveMQ Edge 2026.15 now](https://www.hivemq.com/releases/edge/hivemq-edge-full-2026.15.zip)
