HiveMQ Platform How-Tos

Configure server-side TLS with HiveMQ and Keytool (self-signed)

The next sections give you step-by-step instructions on how to configure server-side SSL/TLS with HiveMQ.
In this scenario, the client only validates the correct server certificate.

Generate a server-side certificate for HiveMQ

  • Execute the following command and enter all prompted information for the certificate:

    keytool -genkey -keyalg RSA -alias hivemq -keystore hivemq.jks -storepass changeme -validity 360 -keysize 2048
    We highly recommend that you update the changeme default to a strong password.
    The first question asks about your first and last name. This is the common name of your certificate. Please enter the URL under which you will connect with your MQTT clients. For example, broker.yourdomain.com (for production) or localhost (for development).
  • Select yes to confirm your entries.

  • Define a password for the newly generated key.

    We highly recommend not to use the same password for the key and the key store.
  • Place the hivemq.jks in the HiveMQ directory and add a TLS listener to the config.xml file.

    <listeners>
    ...
        <tls-tcp-listener>
            <port>8883</port>
            <bind-address>0.0.0.0</bind-address>
            <tls>
                <keystore>
                    <path>hivemq.jks</path>
                    <password>your-keystore-password</password>
                    <private-key-password>your-key-password</private-key-password>
                </keystore>
                <client-authentication-mode>NONE</client-authentication-mode>
            </tls>
        </tls-tcp-listener>
    ...
    </listeners>
    The your-keystore-password and your-key-password passwords depend on the passwords from the previous steps.

Generate a PEM client certificate (mosquitto_pub/_sub)

When you connect with mosquitto_pub/_sub command-line utilities, a PEM file of the certificate is required to allow the mosquitto clients to validate the self-signed certificate. You need to have access to the server key store generated in the above steps.

  • To export a PEM file from the server key store, enter:

    keytool -exportcert -keystore hivemq.jks -alias hivemq -keypass your-key-password -storepass your-keystore-password -rfc -file hivemq-server-cert.pem
    Be sure to replace your-keystore-password and your-key-password in the command with your chosen passwords.
  • To use the PEM with mosquitto_pub, enter:

    mosquitto_pub -t "test/topic" -m "TLS works with client PEM" -p 8883 --cafile hivemq-server-cert.pem

Generate a client JKS trust store (Paho Java)

When you connect with a Java MQTT client, a JKS client key store is required to validate the self-signed certificate. You need to have access to the server key store generated in the above steps.

  • Export the server certificate from the server key store

    keytool -export -keystore hivemq.jks -alias hivemq -storepass your-keystore-password -file hivemq-server.crt
    Be sure to replace your-keystore-password in the command with your chosen password.
  • To generate a client trust store, enter:

    keytool -import -file hivemq-server.crt -alias HiveMQ -keystore mqtt-client-trust-store.jks -storepass changeme
    We highly recommend the use of a strong password instead of changeme.
    • Confirm the certificate with yes, before the trust store is successfully created.

  • Connect with Eclipse Paho

    The following simple example only shows how to test if TLS is working.
    For production usage, a more sophisticated implementation is necessary.
    Connect to HiveMQ with SSL using Eclipse Paho
    private static Logger log = LoggerFactory.getLogger(PublisherSSL.class);
    
    public static void main(String... args) {
        try {
            String clientId = "sslTestClient";
            MqttClient client = new MqttClient("ssl://localhost:8883", clientId, new MemoryPersistence());
    
            MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
    
            try {
                mqttConnectOptions.setSocketFactory(getTruststoreFactory());
            } catch (Exception e) {
                log.error("Error while setting up TLS", e);
            }
    
            client.connect(mqttConnectOptions);
            client.publish("test/topic", "TLS works with client JKS!".getBytes(), 0, false);
            client.disconnect();
    
        } catch (MqttException e) {
            log.error("MQTT Exception:",e);
        }
    }
    
    public static SocketFactory getTruststoreFactory() throws Exception {
    
        KeyStore trustStore = KeyStore.getInstance("JKS");
        InputStream in = new FileInputStream("mqtt-client-trust-store.jks");
        trustStore.load(in, "your-client-keystore-password".toCharArray());
    
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(trustStore);
    
        SSLContext sslCtx = SSLContext.getInstance("TLSv1.2");
        sslCtx.init(null, tmf.getTrustManagers(), null);
        return sslCtx.getSocketFactory();
    }
    Remember to replace the passwords in the snippet with your chosen passwords.

Configure TLS with HiveMQ and Portecle (self-signed)

  • Download and unzip the current version of Portecle.

  • To start Portecle, double-click the provided portecle.jar file or enter java -jar portecle.jar in the console:

    Portecle after start

    Portecle after start

  • To create the server key store, select File → New Keystore from the menu and select JKS as key store type in the popup window:

    Choose Java key store

    Choose Java key store

  • To create a new key pair, select Tools → Generate Key Pair and define the Key Algorithm and Key Size:

    Common Key Algorithm and Size

    Common Key Algorithm and Size

    • Enter the Signature Algorithm ( SHA512withRSA is recommended) and the Certificate Details:

      Certificate Signature Algorithm and Details

      Certificate Signature Algorithm and Details

    • Choose a Key Pair Entry Alias:

      An alias for the key pair

      An alias for the key pair

    • Set a password for the Key Pair Entry:

      A password to protect the private key

      A password to protect the private key

      Successful Generation of Key Pair

      Successful Generation of Key Pair

    • To save the key store, define File → Save Keystore As…​:

      Save the key store

      Save the key store

  • To export the certificate for the client, right-click the certificate key pair and select Export.

    • Select Head Certificate as Export Type and choose an export format ( PEM is recommended):

      Export Details

      Export Details

  • Select Choose directory to save the certificate.

    Export Successful

    Export Successful

  • Next, create the client key store

    • Select File → New Keystore from the menu and JKS as key store type.

    • Import the just saved certificate via Tools → Import Trusted Certificate.

    • Select the previous exported certificate:

      Import server head certificate

      Import server head certificate

    • Confirm the message that the trust path could not be established.
      This is because the certificate is self-signed and no certificate chain can verify it:

      Warning because of the self-signed certificate

      Warning because of the self-signed certificate

    • Confirm the showed certificate details:

      Certificate Details

      Certificate Details

    • To trust the certificate, click Yes.

      Trust the created self-signed certificate for the server

      Accept to trust our created self-signed certificate for the server

    • Enter an alias:

      Alias for the server certificate in the client key store

      Alias for the server certificate in the client key store

      Successful import of the server certificate in the client key store

      Successful import of the server certificate in the client key store

    • Save the key store as client.jks with File → Save Keystore As…​.

  • Place the server.jks in the HiveMQ directory and add a TLS listener to config.xml.

    <listeners>
    ...
        <tls-tcp-listener>
            <port>8883</port>
            <bind-address>0.0.0.0</bind-address>
            <tls>
                <keystore>
                    <path>server.jks</path>
                    <password>your-keystore-password</password>
                    <private-key-password>your-key-password</private-key-password>
                </keystore>
                <client-authentication-mode>NONE</client-authentication-mode>
            </tls>
        </tls-tcp-listener>
    ...
    </listeners>
  • Use client.jks to connect with a client.

Configure TLS with client certificates (self-signed) for HiveMQ using Keytool

Configure with PEM files (for mosquitto_pub/_sub and other clients)

  1. Follow the procedures to Generate a server-side certificate for HiveMQ and Generate a PEM client certificate.

  2. Make sure the server-side TLS works with mosquitto_pub/_sub and HiveMQ.

  3. Generate client certificates.

    This step needs to be done for each client that connects to HiveMQ. Also this is not the only way on how to create certificates. There are different options depending on your use case and capabilities.
    1. To generate a client certificate for PEM-based clients such as mosquitto_sub/_pub, execute the following command for each client:

      openssl req -x509 -newkey rsa:2048 -keyout mqtt-client-key-2.pem -out mqtt-client-cert-2.pem -days 360

      Enter all prompted information for the certificate.
      You end up with two PEM files: mqtt-client-key-2.pem and mqtt-client-cert-2.pem.

  4. Create a trust store for HiveMQ.

    When the client connects with a certificate, HiveMQ needs a trust store in order to validate the self-signed certificates. You need to have access to all certificate PEM files generated in the previous step.

    1. To export the client certificate from the PEM certification file, enter:

      openssl x509 -outform der -in mqtt-client-cert-2.pem -out mqtt-client-cert-2.crt
    2. To generate one common server trust store, execute the following command for each client certificate:

      keytool -import -file mqtt-client-cert-2.crt -alias client2 -keystore hivemq-trust-store.jks -storepass changeme
      We highly recommend the use of a strong password instead of changeme.

      Confirm the certificate with yes, before the trust store is successfully created.

  5. Change the config.xml in the HiveMQ home directory

    <listeners>
    ...
        <tls-tcp-listener>
            ...
            <tls>
                <keystore> ... </keystore>
                <client-authentication-mode>REQUIRED</client-authentication-mode>
                <truststore>
                        <path>hivemq-trust-store.jks</path>
                        <password>your-hivemq-trust-store-password</password>
                </truststore>
            </tls>
        </tls-tcp-listener>
    ...
    </listeners>
    • Connect with mosquitto_pub/_sub to HiveMQ

      In the code example, we use the previously generated client trust store (hivemq-server-cert.pem) and the just generated PEM files to set up a full TLS client authentication to HiveMQ.

      mosquitto_pub -t "test" -m "test" -p 8883 --cert mqtt-client-cert-2.pem --key mqtt-client-key-2.pem --cafile hivemq-server-cert.pem

Configure with Java Key stores (Eclipse Paho Java clients)

  1. Follow the procedures to Generate a server-side certificate for HiveMQ and Generate a PEM client certificate.

  2. Make sure the server-side TLS works with Eclipse Paho and HiveMQ.

  3. To generate a client certificate for each Eclipse Paho Java client, execute the following command for each client and enter all prompted information for the certificate:

    keytool -genkey -keyalg RSA -alias mqtt-paho-client-1 -keystore mqtt-paho-client-1.jks -storepass changeme -validity 360 -keysize 4096
    We highly recommend the use of a strong password instead of changeme.
    This step needs to be done for each client that connects to HiveMQ. Also, this is not the only way to create certificates. There are different options depending on your use case and capabilities.
  4. Generate one common server trust store for HiveMQ.

    When the client connects with a certificate, HiveMQ needs a trust store to validate the self-signed certificates. You need to have access to all client key stores generated in the previous step.

  5. To export the client certificate from each of the client key stores, enter:

    keytool -export -keystore mqtt-paho-client-1.jks -alias mqtt-paho-client-1 -storepass your-client-keystore-password -file mqtt-paho-client-1.crt
    Remember to replace your-client-keystore-password in the command with your chosen key store password.
  6. To generate a server trust store, execute the following command for each client certificate:

    keytool -import -file mqtt-paho-client-1.crt -alias client1 -keystore hivemq-trust-store.jks -storepass changeme
    We highly recommend the use of a strong password instead of changeme.
    1. Confirm the certificate with yes, before the trust store is successfully created.

  7. Change the config.xml in the HiveMQ home directory:

    <listeners>
    ...
        <tls-tcp-listener>
            ...
            <tls>
                <keystore> ... </keystore>
                <client-authentication-mode>REQUIRED</client-authentication-mode>
                <truststore>
                        <path>hivemq-trust-store.jks</path>
                        <password>your-hivemq-trust-store-password</password>
                </truststore>
            </tls>
        </tls-tcp-listener>
    ...
    </listeners>
    • Connect with Paho

      In the code example, we use the previously generated client trust store and the just generated client key store to set up a full TLS client authentication with Eclipse Paho for Java

      This simple example only tests whether TLS is working. For production usage, a more sophisticated implementation is necessary.
      Connect to HiveMQ with SSL using Eclipse Paho
      private static Logger log = LoggerFactory.getLogger(PublisherClientCertSSL.class);
      
      public static void main(String... args) {
          try {
              String clientId = "sslTestWithCert";
              MqttClient client = new MqttClient("ssl://localhost:8883", clientId, new MemoryPersistence());
      
              MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
      
              try {
                  mqttConnectOptions.setSocketFactory(getTruststoreFactory());
              } catch (Exception e) {
                  log.error("Error while setting up TLS", e);
              }
      
              client.connect(mqttConnectOptions);
              client.publish("test", "test".getBytes(), 1, true);
              client.disconnect();
      
          } catch (MqttException e) {
              log.error("MQTT Exception:",e);
          }
      }
      
      public static SocketFactory getTruststoreFactory() throws Exception {
      
          //Create key store
      
          KeyStore keyStore = KeyStore.getInstance("JKS");
          InputStream inKey = new FileInputStream("mqtt-paho-client-1.jks");
          keyStore.load(inKey, "your-client-key-store-password".toCharArray());
      
          KeyManagerFactory kmf = KeyManagerFactory
                  .getInstance(KeyManagerFactory.getDefaultAlgorithm());
          kmf.init(keyStore,"your-client-key-password".toCharArray());
      
          //Create trust store
      
          KeyStore trustStore = KeyStore.getInstance("JKS");
          InputStream in = new FileInputStream("mqtt-client-trust-store.jks");
          trustStore.load(in, "your-client-trust-store-password".toCharArray());
      
          TrustManagerFactory tmf = TrustManagerFactory
                  .getInstance(TrustManagerFactory.getDefaultAlgorithm());
          tmf.init(trustStore);
      
          // Build SSL context
      
          SSLContext sslCtx = SSLContext.getInstance("TLSv1.2");
          sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers() , null);
          return sslCtx.getSocketFactory();
      
      }
      Remember to replace the passwords in the snippet with your chosen passwords.

Connect to an OPC UA server that uses a self-signed certificate

Factory networks often have no certificate authority. Each machine presents a certificate that is issued to itself. Such a certificate does not chain to any anchor in the default JVM trust bundle, so chain validation fails. You can install the device certificate in the truststore as its own trust anchor. This works, but it costs one truststore entry per machine. You must also re-export and redistribute the entry each time the certificate rotates. This how-to uses the lighter fingerprint allow-list workflow instead. It takes you from the first refused connection to a working, encrypted connection whose server certificate is trusted by its fingerprint.

The example uses the freely available Prosys OPC UA Simulation Server, but nothing here is specific to that server. Every log line quoted below comes from an actual run of these steps.

Before you start, make sure you have the following resources:

  • A running OPC UA server that offers a secured endpoint.

  • Administrative access to that server, to trust the HiveMQ Edge client certificate.

  • keytool, which ships with every JDK.

  • An MQTT client, to confirm that data arrives. The example uses the MQTT CLI.

Three different refusals stand between your starting point and flowing data. OPC UA trust runs in both directions. Each refusal has a distinct log signature, quoted in the steps exactly as the adapter prints it. The signature always tells you which refusal you face.

Fixed in Log signature What it means

Step 2

requires a keystore, cannot connect

HiveMQ Edge has no client certificate to present.

Step 3

[remote=…​] Bad_SecurityChecksFailed

The server does not trust the HiveMQ Edge certificate yet.

Steps 5–6

unable to find valid certification path

HiveMQ Edge does not trust the server certificate yet.

1. Start from a refused connection

Configure the adapter as usual and choose a security policy other than NONE. The tag and mapping are what make the result observable at the end. The node ns=3;i=1001 is the counter node of the Prosys simulation server, published to factory/counter. Substitute a node your server offers.

<protocol-adapter>
    <adapterId>simulation-server</adapterId>
    <protocolId>opcua</protocolId>
    <config>
        <uri>opc.tcp://machine-1.factory.local:53530/OPCUA/SimulationServer</uri>
        <security>
            <policy>BASIC256SHA256</policy>
        </security>
        <tls>
            <enabled>true</enabled>
        </tls>
    </config>
    <tags>
        <tag>
            <name>counter</name>
            <description>The simulation server's counter node</description>
            <definition>
                <node>ns=3;i=1001</node>
            </definition>
        </tag>
    </tags>
    <northboundMappings>
        <northboundMapping>
            <tagName>counter</tagName>
            <topic>factory/counter</topic>
        </northboundMapping>
    </northboundMappings>
</protocol-adapter>

The adapter starts, but it does not connect. The reason is the WARN; the ERROR beneath it is the consequence, and it repeats on every retry:

WARN  - OPC UA Security policy 'http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256'
        for protocol adapter 'simulation-server' requires a keystore, cannot connect.
ERROR - Unable to create OPC UA client for adapter 'simulation-server'
UaException: status=Bad_ConfigurationError, message=no endpoint selected
Every security policy other than NONE requires HiveMQ Edge to present its own client certificate. A <keystore> element is therefore mandatory, not only for x509 authentication. Step 2 creates one.

Until step 5, the adapter logs two more warnings at every start. Both are about the default STANDARD preset, which is still in force. Neither of those warnings are about the problem you are solving here. Both stop after step 5 configures SELF_SIGNED. That preset trusts by fingerprint instead of by chain, so no certification path is built and neither warning applies.

  • TLS hostname verification is not enabled. This warning appears wherever a certification path is built without the hostname check, which is what STANDARD does. SELF_SIGNED enables that check.

  • revocation=REQUIRE_CRLS is enforced and the truststore contains a CA, but no certificate revocation list is configured. This warning appears because STANDARD demands revocation checking. Without a <truststore> of your own, the JVM cacerts bundle supplies the trust anchors and is full of CAs. Do not act on it in this how-to: it tells you a CA-signed server would be refused, and the server here is self-signed. SELF_SIGNED resolves revocation to NONE.

Both are described in the validation axes.

2. Give HiveMQ Edge a client certificate

OPC UA identifies an application by the URI in its certificate. The certificate must therefore carry a SubjectAltName URI. Generate a self-signed key pair with keytool:

keytool -genkeypair -alias edge-client -keyalg RSA -keysize 2048 -validity 365 \
  -dname "CN=HiveMQ Edge, O=Example, C=DE" \
  -ext "san=uri:urn:hivemq:edge:client,dns:edge-host.factory.local" \
  -ext "KeyUsage=digitalSignature,keyEncipherment,dataEncipherment,nonRepudiation,keyCertSign" \
  -ext "ExtendedKeyUsage=clientAuth,serverAuth" \
  -keystore edge-client.jks -storepass changeme -keypass changeme
Replace changeme with strong passwords. In the dns: entry, use the real host name of the machine that runs HiveMQ Edge.

Point the adapter at the keystore:

<tls>
    <enabled>true</enabled>
    <keystore>
        <path>conf/edge-client.jks</path>
        <password>changeme</password>
        <privateKeyPassword>changeme</privateKeyPassword>
    </keystore>
</tls>

3. Trust the HiveMQ Edge certificate on the server

OPC UA trust runs in both directions. Until the server trusts the certificate you just created, the connection is refused by the server. The error resembles a problem with the server’s own certificate:

ERROR - [remote=machine-1.factory.local/192.168.1.123:53530] errorMessage=ErrorMessage{
        error=StatusCode[name=Bad_SecurityChecksFailed, value=0x80130000, quality=bad]}

Start HiveMQ Edge once and let it attempt the connection. The server records the certificate it rejected. Most servers place it in a rejected certificates folder and offer a way to promote it to trusted. In the Prosys simulation server, open the Certificates tab. Select the certificate whose subject matches the -dname value that you chose above, CN=HiveMQ Edge, O=Example, C=DE. Trust the certificate, then restart the server.

HiveMQ Edge retries with backoff and picks up the change on its next attempt. Restart HiveMQ Edge only if you would rather not wait out the backoff delay.

This step is easy to mistake for a HiveMQ Edge problem. A failure message with a [remote=…​] prefix comes from the server. Fix it on the server side.

4. Recognize the failure that this how-to solves

With the client certificate trusted, HiveMQ Edge gets far enough to judge the server certificate. It then refuses that certificate:

INFO  - OPC UA adapter has no user truststore configured; falling back to JVM cacerts. If the
        server presents a self-signed certificate that does not chain to a public CA, use
        tlsChecks=SELF_SIGNED to trust it by fingerprint instead.
ERROR - [remote=machine-1.factory.local/192.168.1.123:53530] Exception caught: UaException:
        status=Bad_SecurityChecksFailed, message=sun.security.provider.certpath.
        SunCertPathBuilderException: unable to find valid certification path to requested target

This is the message to recognize. It does not mean the certificate is invalid. It means that the certificate chains to nothing HiveMQ Edge trusts, which is exactly what a self-signed certificate does.

tlsChecks=NONE does not solve this. Despite the name, it still requires the certificate to chain to a trust anchor. It only switches off the checks layered on top. See Certificate validation.

5. Obtain the server fingerprint

Instead of a trust anchor, give HiveMQ Edge the SHA-256 fingerprint of the specific certificate to accept. You can obtain the fingerprint in three ways:

  • From the device vendor. A fingerprint is short enough to send by email or read out over the phone. This is what makes the approach workable when no CA exists.

  • From the certificate file, if you have it:

    openssl x509 -in server-cert.pem -noout -fingerprint -sha256
  • From the HiveMQ Edge log, as shown below.

To use the log, create the allow list with a placeholder entry and let the connection fail once:

# Fingerprints of the OPC UA servers this Edge is allowed to talk to.
# Placeholder so the adapter starts; replace with the real fingerprint.
0000000000000000000000000000000000000000000000000000000000000000
The placeholder line matters. An allow list that contains no fingerprints stops the adapter from starting, because an empty allow list would reject every server: Certificate allow-list '…​' contains no fingerprints.

Configure the SELF_SIGNED preset and point it at the file:

<tls>
    <enabled>true</enabled>
    <tlsChecks>SELF_SIGNED</tlsChecks>
    <allowList>
        <path>conf/opcua-fingerprints.txt</path>
    </allowList>
    <keystore>
        <path>conf/edge-client.jks</path>
        <password>changeme</password>
        <privateKeyPassword>changeme</privateKeyPassword>
    </keystore>
</tls>

The adapter now reads the allow list at start. The placeholder counts as an entry, which is why the INFO line reports one fingerprint. The rejection names the certificate that the server presented, in the exact format the file accepts:

INFO - OPC UA adapter endpoint 'opc.tcp://machine-1.factory.local:53530/OPCUA/SimulationServer':
       server certificates are trusted by fingerprint; 1 fingerprint(s) loaded from
       'conf/opcua-fingerprints.txt'.
WARN - OPC UA adapter endpoint 'opc.tcp://machine-1.factory.local:53530/OPCUA/SimulationServer':
       the server certificate was rejected, its SHA-256 fingerprint is not in the configured
       allow-list. Subject='DC=machine-1.factory.local,O=Prosys OPC,CN=SimulationServer@machine-1',
       issuer='DC=machine-1.factory.local,O=Prosys OPC,CN=SimulationServer@machine-1',
       fingerprint=8c:6c:ce:4e:be:50:a0:f6:52:75:c1:5a:f3:27:28:a9:a3:71:13:45:e0:ae:36:f6:0b:fd:
       62:84:4e:dc:95:20. If this is the expected server, add the fingerprint to the allow-list
       file, then restart the adapter - the allow-list is read once at adapter start.
Read the subject and issuer before you trust a fingerprint taken from the log. At that moment nothing has verified the certificate, so only do this on a network where you can be sure no attacker is interposed. A fingerprint obtained from the vendor is the safer route.

6. Add the fingerprint and connect

Replace the placeholder with the fingerprint from the log:

# Fingerprints of the OPC UA servers this Edge is allowed to talk to.

# machine-1 - Prosys simulation server
8c:6c:ce:4e:be:50:a0:f6:52:75:c1:5a:f3:27:28:a9:a3:71:13:45:e0:ae:36:f6:0b:fd:62:84:4e:dc:95:20

Restart HiveMQ Edge. The first line is the same one step 5 produced. What marks success is that no rejection follows it:

INFO - OPC UA adapter endpoint 'opc.tcp://machine-1.factory.local:53530/OPCUA/SimulationServer':
       server certificates are trusted by fingerprint; 1 fingerprint(s) loaded from
       'conf/opcua-fingerprints.txt'.
INFO - OPC UA subscription created with publishingInterval=1000.0ms (requested 1000ms)
INFO - OPC UA adapter 'simulation-server' connected successfully

Subscribe to the topic from the mapping in step 1 and you will see the counter values arriving over the OPC UA connection that you just secured: encrypted, and from the server whose fingerprint you enrolled:

mqtt sub -h localhost -p 1883 -t 'factory/#'
What is encrypted here is the OPC UA hop between HiveMQ Edge and the device. The MQTT hop in this command uses the plain listener on port 1883. That is acceptable on localhost but it is not encrypted. To protect MQTT traffic that leaves the machine, configure a TLS listener and subscribe through it (typically port 8883 with the appropriate trust options). See Secure TCP Listener.
{
  "value" : 19,
  "timestamp" : 1785944119747
}

7. Resolve Bad_CertificateHostNameInvalid or Bad_CertificateUriInvalid

The SELF_SIGNED preset also requires the certificate to identify the endpoint. The certificate must carry the expected ApplicationUri and a host name that matches the endpoint. Device certificates sometimes carry neither. If you see one of these status codes, switch from the preset to the individual axes and relax only the check that fails. The following configuration drops the hostname check, which resolves Bad_CertificateHostNameInvalid:

<tls>
    <enabled>true</enabled>
    <tlsChecksFull>
        <trustMode>ALLOW_LIST</trustMode>
        <hostname>NONE</hostname>
        <revocation>NONE</revocation>
        <keyUsage>NONE</keyUsage>
    </tlsChecksFull>
    <allowList>
        <path>conf/opcua-fingerprints.txt</path>
    </allowList>
    ...
</tls>

For Bad_CertificateUriInvalid relax sanUri instead. Replace <hostname>NONE</hostname> with <sanUri>NONE</sanUri>, which keeps the hostname check enforced.

Omit an axis you do not want to set. Do not leave its element empty. An empty element in first position collapses the whole block and stops the adapter from starting. An empty element in any later position, such as <hostname></hostname> in the recipe above, silently means the axis is unset. An unset axis resolves to its strictest value. That is the exact opposite of the NONE you wanted, and nothing refuses the configuration to tell you. A misspelled axis name is caught. For example, <trustmode> rather than <trustMode> stops the adapter at start-up and names the entry, rather than leaving the axis at a default you did not choose. Note also that revocation and keyUsage must be set to NONE explicitly here. Each omitted axis takes its strictest value, and the SELF_SIGNED preset you are migrating from requires neither. revocation needs a certification path, which ALLOW_LIST does not build. keyUsage is relaxed because device certificates frequently carry no key-usage extensions. Leaving it out would refuse exactly those certificates with Bad_CertificateUseNotAllowed.

What this does and does not protect against

The allow list is a trust set. The adapter accepts any certificate whose fingerprint appears in its file. A per-adapter file that holds exactly one fingerprint is what this how-to builds, and it amounts to pinning one specific certificate. It detects the replacement of that certificate. If the device certificate is rotated, or a different machine answers on the same address, the connection fails until you deliberately add the new fingerprint.

Several fingerprints in one file, or one file shared across adapters, weakens this guarantee. Every listed certificate then passes the trust decision on every adapter that uses the file. Identity checks become the only way to tell listed servers apart. If you relaxed hostname or sanUri in step 7, a different listed machine answering on this adapter’s address is not detected. When single-certificate pinning matters, keep one file per adapter with exactly the one fingerprint that adapter should accept.

None of this establishes that the certificate was genuine in the first place. Whoever writes the allow list trusts the channel that delivered the fingerprint: the vendor’s email, a phone call, a device label. This is the same limitation as the first ssh connection to a new host. Treat the fingerprint with the care you would give the certificate itself.

For the full model, including all six validation axes and a table that maps connection errors to their causes, see the OPC UA TLS configuration reference.