Creating and Using Client Certificates with MQTT and Mosquitto

Another popular way of authenticating clients is via client certificates and can be use as in addition or as an alternative to using user name and password authentication.

In cryptography, a client certificate is a type of digital certificate that is used by client systems to make authenticated requests to a remote server.

Client certificates play a key role in many mutual authentication designs, providing strong assurances of a requester’s identity. –Wiki

A client certificate identifies the client just like the server certificate identifies the server.

Normally certificates are created and distributed to each client that connects to the server/broker that requires them.

However you can share a client certificate between clients.

As with username and password authentication the broker dictates whether or not a clients need to supply a certificate.

You can use certificates in combination with username and password authentication.

Mosquitto Broker Configuration

The main two settings are:

  • require_certificate – Main setting tells client it needs to supply a certificate when set to true. Default false
  • use_identity_as_username– – When set to true it tells mosquitto not to use the password file but to take the username from the certificate (common name given to certificate when you create it). Default false
  • crlfile – You can create a certificate revocation file that is used to revoke a client certificate

Creating Self Signed Client Certificates

The client and server must use the same CA (certificate Authority)  for the client and server certificates.

You create the client certificates using the same process as you used for creating a server certificate.

  1. Create a client key  don’t password protect.
  2. Create a client certificate request using the key.
  3. Use the CA key to sign the client certificate request from step 2.

Preparation –

You need an existing CA certificate and private key which you get when you follow the steps for creating your own self signed server certificate.

You need to use the same CA for the client certificates as the server certificate, and the broker needs to use SSL.

This is because  client certificates require an encrypted connection.

If you don’t have a CA certificate then you need create one using the following:

First create a key for the CA

Command is:  openssl genrsa -des3 -out ca.key 2048

create-ca-key

Note: it is OK to create a password protected key for the CA.

Next:  Create a certificate for the CA using the CA key that we created in step 1

Command is:  openssl req -new -x509 -days 1826 -key ca.key -out ca.crt

create-ca-certificate

If you have followed the tutorial on creating server certificates then your folder should look like the one below:

ssl-directory

Step 1

The first step is to create a client private key.

The command is:

openssl genrsa -out client.key 2048

create-client key

Step 2

Next create a certificate request and use the client private key to sign it.

The command is:

openssl req -new -out client.csr -key client.key

You will be presented with a form that you need to complete.

The most important entry is the common name. This name can be used by the broker to identify the client in place of a username.

client-certificate-request
Normally this certificate would be sent to a Certificate authority, but we are our own Certificate authority so we complete the request to create a client certificate

Step 3

Now we complete the request and create a client certificate. The command is:

openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 360

create-client-certificate

This is now what our directory looks like

client-cetificates-final-folder

Using Client Certificates

To use client certificates the client requires three files:

  • ca.crt – The Certificate authority certificate
  • client.crt – The client certifcate file
  • client.key – The client private key

Publishing using Mosquitto_pub tool

The command is:

mosquitto_pub --cafile C:\ssl\ca.crt --cert C:\ssl\client.crt --key C:\ssl\client.key -d -h 192.168.1.157 -p 8883 -t test -m "hello there"

using-client-certificates.jpg

Note: You need to use the server name that is on the server certificate. If I use the IP address instead I get this error.

using-client-certificates-error

Publish Using Python

If you use Python you need to set the TLS settings  using:

client.tls_set('c:/ssl/ca.crt','c:/ssl/client.crt',\
'c:/ssl/client.key')

Publish Using Node-Red

On Node red you need to enable the SSL/TLS option in the broker settings.

tls-node-red

and then upload the client files as shown in the screen shot below:

client-certificates-node-red

Mosquitto Broker Connection

When the client connects to the broker and the use_identity_as_username is true then this is what you see:

mosquitto-broker-client-certs

Resources:

Example Mosquitto configuration file:

port 1883
log_type error
log_type notice
log_type information
log_type debug
#allow_anonymous false
#password_file /etc/mosquitto/pass.txt
#Extra Listeners
listener 8883
#ssl settings
cafile /home/steve/mos/certs/ca.crt
keyfile /home/steve/mos/certs/server.key
certfile /home/steve/mos/certs/server.crt
#client certifcate settings
require_certificate true
use_identity_as_username true

Terms Used

CA= Certificate Authority
Private Key = An encryption key that isn’t shared and needs to be stored securely
Public Key= An encryption key that is shared and doesn’t needs to be stored securely.
Certificate Request = An application for a certificate made to a certificate authority. Like a passport application

Shell Scripts

To save you typing I’ve created two Linux shell scripts that run the commands and create server and client certificates and keys as in this tutorial and the server certificate tutorial.

download

Related Tutorials

Please rate? And use Comments to let me know more

157 comments

  1. I am not using client certificate.
    Just configured the ca, server.cert and server.key and tested the broker with mqttx

    it works with SSL/TLS set to ON
    and SSL secure if ON it says Error: Self Signed Certificate

    1. Hi can you explain this a little more
      t works with SSL/TLS set to ON
      and SSL secure if ON it says Error: Self Signed Certificate
      rgds
      steve

  2. FYI the blog post says “require_certificates” but it needs to be singular not plural: “require_certificate”

    Otherwise thanks for the help it works great!

  3. Hey Sir,
    i really appreciate the work you do, Now i understand more about MQTT and SSL/TLS connection, following your steps i managed to create a secure connection between my broker hosted on a droplet and my laptop as client, with paho python lib i can PUB/SUB to the broker. However, I copied the script with the ca.crt, client.crt and the client.key files to my rpi to run the same test but it won’t work, this is what i get when i check the mosquitto log file of my broker:
    OpenSSL Error[0]: error:0A000126:SSL routines::unexpected eof while reading

    is it because i use the same certificate for both devices?
    this is my script:
    import paho.mqtt.client as mqtt
    import os,sys
    import json
    import logging
    import ssl

    #Const
    BROKER = “mydewarmtebeta.com”
    PORT =8883

    device = “””{
    “name”: “TEST-9”,
    “type”: “AO”
    }”””

    #on published
    def on_publish(client, userdata, rc):
    print(“Data Published \n”)

    #On connect
    def on_connect(client, userdata, flags, rc):
    if rc == mqtt.MQTT_ERR_SUCCESS:
    print(“Connected to the broker”)
    else:
    print(f”Connection failed with return code: {rc}”)

    def on_disconnect(client, userdata, rc):
    print(“client disconnected ok”)

    def on_log (client, userdata, level, buf):
    print(“buffer”, buf)

    #Create a mqtt client and publish payload

    client = mqtt.Client(“devicemanager”)
    client.on_log = on_log
    client.enable_logger(logging.getLogger(__name__)) # Enable debugging logs

    client.tls_set(ca_certs=”/home/pi/mqtt/MQTT_new_device/ca.crt”, certfile=”/home/pi/mqtt/MQTT_new_device/addevicemanager-certs/client.crt”, keyfile=”/home/pi/mqtt/MQTT_new_device/addevicemanager-certs/client.key”)
    client.tls_insecure_set(True)
    client.connect(BROKER, PORT)
    client.on_connect = on_connect

    TOPIC = “mydewarmte/add/device/TEST-9”

    try:
    ret = client.publish(TOPIC, str(device))
    if ret.rc == mqtt.MQTT_ERR_SUCCESS:
    print(“Data Published Successfully”)
    else:
    print(f”Data Publish Failed with return code: {ret.rc}”)

    except Exception as e:
    print(f”An error occurred: {str(e)}”)

    client.on_publish = on_publish

    1. You can’t use the same sever cert on the pi unless it has the same name or ip address as the droplet. Try creating new certificates for the pi.
      Rgds
      Steve

      1. Yep, it works for me now after I created a new cert for the PI, From what I understand, if I want to use an SSL/TLS connection I have to generate a certificate for every client which is different from using a username/password authentication because using the second method I’m allowed to connect to the broker using the same username/password from other devices.

        1. Glad It is working but I’m not sure you need multiple client certificates. I will try it but perhaps as you are alread set up you can give it a quick try and let me know.

          Checked and you can use same cert on all clients.

  4. Hi Steve, as everyone here I read your tutorial and tried to setup my own client certificates, I read some other tutorials as well to get to know the issue better. When running both the broker and clients on one machine there’s no problems however when the clients are running on a remote device in the same LAN, TLS error occurs: OpenSSL Error[0]: error:0A000412:SSL routines::sslv3 alert bad certificate.
    I’ve described the issue thoroughly on stack overflow (https://stackoverflow.com/q/76539618/11287083), maybe you know how to fix this?

    Thanks for the tutorial!

      1. Moreover, It really seems impossible to configure MQTT with TLS but without client certification. Any attempt of mine end with below messages on client’s and server’s side:

        client:

        mosquitto_pub -h workmachine -p 8883 -t test -m test –cafile ca/ca.crt –tls-version tlsv1.2
        Connection error: Connection Refused: not authorised.
        Error: The connection was refused.

        server:

        1687766939: New connection from 127.0.0.1:42958 on port 8883.
        1687766939: Sending CONNACK to 127.0.0.1 (0, 5)
        1687766939: Client disconnected, not authorised.

        It seems that this mechanism isn’t supported by TLS v1.2.

        1. The not authorised message looks like you are not allowing anonymous access.
          You cannot use client certificates without SSL. So you need to get SSL working first.
          Rgds
          Steve

          1. What do you mean by without SSL? Shall I then make the TLC connection work with remote clients and anonymous access being turned on first?

          2. Yes you first need ssl working before you can use client certificates.
            Rgds
            Steve

          3. I understand. I have clients working with SSL and no client cerst, but only locally – on the same machine as broker. Do you know what could cause the rejection of the clients from outside of the local node?

          4. It could be a firewall setting or something in the mosquitto.conf file. Can you show be the file.
            Rgds
            Steve

          5. Okay, the problem is now solved, it was just that the client didn’t have the right date and time and the certificate wasn’t yet valid. All fixed now, thank you for your time and tips!

  5. thank you for your response.
    after starting mosquitto broker i am getting this issue. i checked the port is enabled or not C:\Program Files\mosquitto>mosquitto_pub –cafile “C:\Program Files\mosquitto\ca.crt” –cert “C:\Program Files\mosquitto\client.crt” –key “C:\Program Files\mosquitto\client.key” –tls-version tlsv1.2 -h localhost -p 8883 -t test -m “hello there” -d
    Client null sending CONNECT
    Error: protocol error
    while starting this is what i get.
    C:\Program Files\mosquitto>mosquitto -v -c mosquitto.conf
    1687342474: mosquitto version 2.0.15 starting
    1687342474: Config loaded from mosquitto.conf.
    1687342474: Opening ipv6 listen socket on port 8883.
    1687342474: Error: Only one usage of each socket address (protocol/network address/port) is normally permitted.
    why ipv4 listen socket on port 8883 is not opening i dont know.

  6. hi
    i am following same steps but i am unable to start my broker after editing config file (net start mosquitto). what shall i do . if i use start mosquitto -v it is showing “1687161928: Opening ipv4 listen socket on port 1883.
    1687161928: Opening ipv6 listen socket on port 1883.” it is not showing for 8883

  7. Thank you for your detailed post.

    I am using ESP8266 to connect securely to my cloud mqtt broker. but not working for some reason.

    After following your steps, I was able to connect normally to the broker using mosquitto_pub
    mosquitto_pub –cafile ca.crt –cert client.crt –key client.key -d -h mqtt.example.com -p 8883 -t test -m “hello there”

    When connected through ESP8266, the broker logs show this error:

    OpenSSL Error[0]: error:140350E5:SSL routines:ACCEPT_SR_CERT:ssl handshake failure
    Client disconnected: Protocol error.

    Can you please help with this issue.

  8. Hi Steve,
    thanks for the great tutorial.
    But I have a question: I’m trying for days to create a certificate for Activemq Broker Server and windows Cleint. Can I use the tutorial also? works also with Activemq?
    Thanks for the answer.

  9. Hi,
    Thanks for making this guide. I am trying to configure TLS for my Mosquitto Broker and my client(ESP32).
    I have created my own CA and created a broker certificate and a client certificate by signing the CSR that I created using Openssl.

    In my node-red I am able to connect to the MQTT broker just fine, however when I try to connect from my ESP32 using the WiFiSecureClient library, it gives me this error:

    -2WiFiClientSecure client state:
    X509 – Certificate verification failed, e.g. CRL, CA or signature check failed

    Does it have to do with the common name or maybe something else?

    Any help would be appreciated. Thanks !

    1. Common name is a common one and the place to start. You need to access the broker using the sane name as you used for the common name on the certificate.
      So the common name you use on a certificate is the same as you would use to ping the broker.
      Rgds
      Steve

      1. My MQTT broker is running on an EC2 instance, so it has a public IP address. In the common name, do I put the IP address or do I use a common name like MQTTBroker.
        Must I change the hostname of my server ?

        1. The common name is the name you usually use to access the broker.So if you use the IP address then that is also used as the common name.
          However you have already created the certs and so what did you use as the common name.
          If that name cannot be used to ping the broker then you will need to recreate the certificates.
          As you are using a ED2 instance I would also check the firewall ports are open.
          Rgds
          Steve

  10. Hi Steve,
    I am trying to establish MQTT client authentication based on both client certificate with `require certificate true` option along with username/password which have been created using `mosquitto_ctrl dynsec` commands. So that we can apply ACLs on client specific topics based on the created usernames.
    While testing we observed that we could not able to both (client certificate and username/password) for authentication purposese.

    Lemme explain the scenario:
    Let us say we have two clients who wants to connect to our MQTT broker. Broker has single listener 1883 with dynsec-plugin enabled and require certificate true in conf file.
    1. Created client certificates for both the clients (public-private key) by requesting from our CA, who has given Broker/Server certificate as well.
    2. Created username/password for each client and set ACLs for each user via dynsec commands.
    3. Client-1 and Client-2 can establish connections to broker by providing respective client_cert and username password and acls are getting applied properly.
    But if we interchange pub-key/pri-key of client-1 and client-2 and use their respective username/password still the connections are working. I mean client-1 using pub/pri-keys of client-2 with client-1 username/password can still able to establish the connection and vice-versa.

    Scenario-2:
    If we enable `use_identity_as_username true` in the conf, username/password is getting completely ignored which have been set using dynsec plugin cli.

    So does this mean we can use either client certificate or username/password authentication to broker.? We can not use both.
    I am referring to your statement: First line in this post
    Another popular way of authenticating clients is via client certificates and can be use as in addition or as an alternative to using user name and password authentication.

    Kindly share your comments.
    Thanks

    1. Hi
      The way I understood it to work is that you use one method or the other but not both together.
      I have never tested using both together but logically I would expect that one method would get preference over the other as it would be difficult to merge them.
      Does that make sense
      Rgds
      Steve

      1. Thanks Steve for your reply.

        Yeah looks like we can use only one method. Using both the methods does not add any extra security I think.
        Based on the requirements and MQTT client compatibility we need to make a decision to use which method.

      2. Thanks for the reply.
        We can use only one method based on the requirement. Having two methods does not add any extra security.

        Yeah got it what you meant.

  11. Hi Steve,

    I have followed the steps you explained but when trying to publish a message with the following command:

    sudo mosquitto_pub –cafile /etc/mosquitto/ca_certificates/ca.crt –cert /etc/mosquitto/client/client.crt –key /etc/mosquitto/client/client.key -d -h 192.168.1.254 -p 8883 -t test -m “hello there”

    The following error appears:

    Error: Problem setting TLS options: File not found.sudo mosquitto_pub –cafile

    I would like to know if you could help me because I have all the files at the filepaths given and I don’t understand the issue.

    Regards,

    María

    1. Have you tried mosquitto_pub before as it may not be installed? The other alternative is again missing file or permissions.
      rgds
      Steve

  12. Working configuration for MQTTFx.

    mosquitto.conf settings ::::
    listener 8884
    certfile /etc/mosquitto/certs/server.crt
    cafile /etc/mosquitto/ca_certificates/ca.crt
    keyfile /etc/mosquitto/certs/server.key
    tls_version tlsv1.2

    MQTTFx settings – version 1.7.1 ::::
    Under SSL/TLS option do the following.
    Enable SSL/TLS
    Protocol TLSv1.2
    select the option self signed certificates
    Browse and select the files for the options CA file, Client certificate file and Client Key file.
    Leave the client key password empty
    Select PEM Formatted

    Apply / Ok and connect

  13. Hello Steve,
    I used your tutorial on setting up the MQTT for TLS/SSL and got everything working quickly between to RPIs from the command line and a python program. My ultimate goal is to use this for controlling my RPI/Arduino home IoT projects from my Android cell phone when I am remote. I have no problem making the connection with the phone when not using TLS/SSL. Do you have any idea what files are required on the Android to make the connection? I have tried just the CA.crt. I made client.crt and client.key and included them but it still won’t connect (although I can’t copy the key files in the RPI GUI file manager, I had to move them to a usb drive from the command line and even then it said there was an error but seemed to move them). Any help would be appreciated.

    1. It should only be the ca file that is needed. Have you tried using mqtt box as that allows you to specify the location of the CA file.
      What are you using on the phone is it chrome or an APP that you have created.

      1. It is an app that I created using MIT AppInventor 2 with the Ullis Roboter Seite extension that creates a UrsPahoMqttClient. These are the fields available in the properties.
        Broker (I putt in the IP of my broker),
        ClientCertFile (I have left blank and put in a client cert that I generated using your tutorial),
        ClientID (I have left blank and put in name off of client cert file),
        ClientKeyFile (I have left blank and put in key file generated from the tutorial),
        ClientKeyPassword (Always left this blank),
        ClientKeystoreFile (Always left blank),
        ClientKeystorePassword (Always left blank),
        ClientPemFormatted (Checkbox always left unchecked, I was trying to create a BKS file but could never get it to work either with Windows keytool or RPI’s. Kept telling me it couldn’t find the BouncyHouse Provider),
        ConnectionTimeout (Set at 60 seconds),
        KeepAlive (Set at 60 seconds),
        MaxInflight (Left a default of 10),
        Port (8883),
        Protocol (Tried both SSL and TLS),
        TimeToWait (Set at -1 which should be indefinite),
        TrustedCertFile (Always set to the CA File generated by the tutorial),
        TruststoreFile (None),
        TruststorePassword (None),
        UserName (None),
        UserPassword (None).
        I went to the Windows OpenSSL today and I was able to move all files back and forth without the errors I was getting yesterday from the RPI.
        The first error I get states “java.security.spec.InvalidKeySpecException: com.android.org.conscrypt.OpenSSLX509CertificateFactory$ParsingException: Error parsing private key”

        The second error is “javax.net.ssl.SSLHandshakeException: No subjectAltNames on the certificate match”
        I know using App Inventor is kind of cheesy but I mostly enjoy the aspect of interacting with the world through my projects so I’ve primarily devoted my time to learning C, C++, and python and how to use them with the Arduinos, Raspberry, and the Photons. I just use the android for controls and hoping in the future to use it for camera video. I’ve been searching for a way to make this work for pretty much 4 days solid without any success. It is rare that I ask for help, I usually can find something online that points me to the answer if I search long enough but this one has me stumped. Again, your tutorials are awesome and I have learned a lot. thanks for any ideas you can throw my way.

        1. I can only suggest trying it with the mosquitto test broker
          see this link for details
          https://test.mosquitto.org/

          There is an option for a lets encrypt SSl connection.
          I assume you are using it currently with your own mosquitto broker. The latest versions only support ssl 1.2 and above.
          Rgds
          Steve

          1. Thanks Steve. I will give that a try on the weekend. Yes, I am using it with my own broker set up per your tutorial. Using two RPIs I can subscribe and publish with no problems, including a python program from the GUI. Your guides were spot on and everything clicked easily between the computers. I just can’t get the phone to cooperate in the TLS/SSL mode. It works great also when not encrypting. Even with a password and username. I appreciate all the help you provided.

  14. Hi Steve.

    I’m running a broker on a public IP, so i signed its certificate through a public root ca (Sectigo AAA), the same i’m using in same server nginx share for https.
    Now i would have local brokers run as bridge and connect to main one via certificate-based tls.
    No way to have these signed by public authority, cause i have to verify my domain and they run in private networks.
    Any suggestions?
    Thanks in advance,
    best regards

    1. I know **The client and server must use the same CA (certificate Authority) for the client and server certificates**. Just trying to find a workaround

    2. You can use the private cert on the cloud broker as are connecting your private broker to it.
      Does that make sense?
      Rgds
      Steve

      1. Local devices are connected only to local brokers, cause low resources don’t allow encryption.
        So, i will set two different listenners on cloud broker: one with CA verified cert, for secure connections, websocket, etc, and the other for bridges with private self signed certs?
        Yep, it should work 🙂
        Thanks

  15. Hi Steve

    We have a dockerized microservice that is running on Ubuntu 18.04 which allows registration of devices. As part of registration, the microservice receives self-signed certificates from the device which are stored in local database along with thumbprints. For future HTTPS communication, this self-signed certificate and the corresponding thumbprint is used to verify the incoming requests. This works well with HTTPS channel. We need similar authentication/verification for the MQTT channel as well using Mosquitto broker.

    1. Given that each device generates its own self-signed certificates, what are the options we have in this scenario?

    2. Is it possible to store all the self-signed certificate in some trust store where Mosquitto can access and validate?

    3. Are there any plugins available that can do this?

    4. In the absence of any off-the-shelf plugins as mentioned in point number 3 above, is there an option where we can register our own custom written plugins that can be used to verify with our own code?

    Appreciate your suggestions on how we can secure the MQTT connection in this case.

    1. Hi
      If you want it to work like your http clients then you will need to wrtie your own plugin. Mosquitto is going down the plugin route so doing so will get much easier.
      Here is an example from a few years ago
      https://github.com/jpmens/mosquitto-auth-plug
      They have also created their own plugin but it doesn’t do certificates you can read about it here
      http://www.steves-internet-guide.com/understanding-mosquitto-dynamic-security-plugin/

      Sorry I can’t be more help
      Rgds
      Steve

  16. Hey steve, I have few Raspberry pi MQTT Mosquitto clients and would like to have unique certificate for all of them. What would be easy method to generate unique client certificate or any automated process you can recommend? Thanks

  17. I have a Mosquitto broker and apache2 web server running ssl using a proper certificate rather than self signed. I am considering using the client certificate side of the Mosquitto but the above article really discusses the self signed certificate route. I am not sure my certificate authority will issue multiple client certificates. Is this something that needs to be done via them or can be done using OpenSSL. Another route to this is to leave the website certificate in place and create self signed CA certificate and client certificates just for the Mosquitto Broker. Any thoughts on this approach ?

    1. Not sure either re CA and client certificates. You need the CA to generate them I’m pretty sure you can do it with lets encrypt but haven’t tried it.
      The only disadvantage of using your own CA is if it needs public access via websockets and then you get a browser warning.
      Rgds
      Steve

  18. Hi Steve,
    Great article! I followed every step using the Windows name for the computer as common name and everything works perfectly. However, when trying the IP as common name (I also used the IP as server in the Node-Red client) the client doesn’t connect and shows the following error:

    1622623498: Client disconnected: protocol error.
    1622623513: New connection from 192.168.0.67:59274 on port 8883.

    Meanwhile, using mosquitto_pub and mosquitto_sub with the same IP (common name) it does work. And it also works fine in Node-Red when I disable the “Verify server certificate”. I am really interested in being able to use the IP as the name of the server correctly. Could you help me please?

    Thanks

    1. Sorry a bit confused as what works and what doesn’t. If you need to disable verify server certificate then you have a cmmon name conflict. the name you use to connect tot he server in the mqtt connect must match the common name on the certificate that you created.
      Does that make sense?
      Rgds
      Steve

  19. Hi Steve and thanks a lot for this tutorial, it really helped me!!!
    I’m having problem with the “Verify server certificate”, when I enable it it doesn’t work and on the mosquitto server log I see:
    New connection from 172.20.0.10:36458 on port 8883.
    Client closed its connection.

    With that option unchecked, it works without any problem.
    What could that be?
    Thanks!!!

    1. This is usually a common name mismatch on the certificate usually because you have common name of testserver.com on the certificate but you access it from the client using its ip address 192.168.1.1 .
      the names must match.
      rgds
      steve

  20. Hi Steve

    I am trying to publish data from my client to local install mqtt broker through TLS/SSL Connection.

    I have a mqtt broker install in my first PC.

    I created CA, Server & Client Cert Key base on your steps above.

    My Conf.file is defined as below.
    # =================================================
    port 8882
    cafile C:\Users\Desktop\certs\ca.crt
    certfile C:\Users\Desktop\certs\server.crt
    keyfile C:\Users\Desktop\certs\server.key
    require_certificate true
    use_identity_as_username true
    tls_version tlsv1.2
    # ===================================================
    In the first PC I am able to publish and subscribe.. You can refer to the command below.

    mosquitto_pub –cafile C:\Users\Desktop\certs\ca.crt –cert C:\Users\Desktop\certs\client.crt –key C:\Users\Desktop\certs\client.key -d -h LAPTOP -p 8882 -t testing -m “hello there”
    Client mosq-tjqNowdNYBtFWZpLAu sending CONNECT
    Client mosq-tjqNowdNYBtFWZpLAu received CONNACK (0)
    Client mosq-tjqNowdNYBtFWZpLAu sending PUBLISH (d0, q0, r0, m1, ‘testing’, … (11 bytes))

    mosquitto_sub –cafile C:\Users\Desktop\certs\ca.crt –cert C:\Users\Desktop\certs\client.crt –key C:\Users\Desktop\certs\client.key -d -h LAPTOP-C4UNUP7O -p 8882 -t testing
    Client mosq-7ZkwwrrhAaxHwO6Zb7 sending CONNECT
    Client mosq-7ZkwwrrhAaxHwO6Zb7 received CONNACK (0)
    Client mosq-7ZkwwrrhAaxHwO6Zb7 sending SUBSCRIBE (Mid: 1, Topic: testing, QoS: 0, Options: 0x00)
    Client mosq-7ZkwwrrhAaxHwO6Zb7 received SUBACK
    Subscribed (mid: 1): 0
    Client mosq-7ZkwwrrhAaxHwO6Zb7 received PUBLISH (d0, q0, r0, m0, ‘testing’, … (11 bytes))
    hello there
    Client mosq-7ZkwwrrhAaxHwO6Zb7 sending PINGREQ
    Client mosq-7ZkwwrrhAaxHwO6Zb7 received PINGRESP
    Client mosq-7ZkwwrrhAaxHwO6Zb7 received PUBLISH (d0, q0, r0, m0, ‘testing’, … (11 bytes))
    hello there
    _______________________________________________________________________________________________

    I copy the CA & Client Cert & Client key over to second PC that is running in the same network as my mqtt broker ( installed in first PC ) and publish through the command below.

    mosquitto_pub –cafile C:\Users\OneDrive\Desktop\certs\ca.crt –cert C:\Users\Desktop\certs\client.crt –key C:\Users\certs\client.key -d -h LAPTOP -p 8882 -t testing -m “hello there”
    Error: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.

    Please advise.
    Thanks
    Ng

  21. Hi Steve,

    I have been trying to do this process with LetsEncrypt. I have successfully generated the Client Certificate and Client Key, but unable to authenticate.

    It is giving me the following error:

    Client (null) sending CONNECT
    OpenSSL Error[0]: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed
    Error: A TLS error occurred.

    Please guide me with the corrections.

    Thank you.

    1. Try setting the insecure option in the client as it could be a name error. What client are you using and what name/ip are you using to connect to the broker.

      1. Hello Steve,

        Thank you for replying.

        Insecure option It didn’t work.

        I have tried mosquitto_pub as well as Mqtt.fx.

        Thank you.

        1. Then it is probably your certificates. Have you got it working with just ssl and not client certificates?
          Rgds
          Steve

          1. Hi Steve,

            Yes, I got it working with SSL without client certificates. But, it’s not working with Client Certificates.

            I think you can get certificate details by this command:
            openssl s_client -connect mqtt.tattva.cloud:8883

            Please check.

            Regards,
            Punit

          2. I can only suggest you recreate the client certs. What resource are you using to create these certificates?

  22. Hi Steve,

    I am trying to use mqtt over websockets, so I would like to use CA certificates my browser will view as secure. I have been running into problems with this. I have a cloudflare account and it is possible to create client certificates with their service for free, but I have a quick question about this. I basically just create the a private key and a CSR and then use this cloudflare service to sign this CSR. I can do these steps for multiple devices & the broker which will allow me to use TLS? Sorry if this is an overly basic question

      1. Great! Thanks Steve. Also, a related side question. When using MQTT in a browser that already has an SSL certificate — do I need to have another set of private key & certificate credentials in the browser specifically for MQTT(which seems like a dangerous security risk).

        Here is the same original question but with added detail:

        I generate a private key and a client signing request with openssl. Then , under my domain in cloudflare >> SSL/TLS >> Client Certificates >> Create Client Certificate >> Use My Own Private Key & CSR>> I copy the openssl CSR to cloudflare which generates a certificate. I am now left with a cloudflare signed certificate and a private key. However, for the mqtt credentials to work I need the ca.crt – The Certificate authority certificate. This is what has alluded me so far.

        As a sidenote- when trying to publish to the mosquitto broker using my domain name WHILE my domain is “orange clouded” in the cloudflare dashboard–meaning traffic is proxied through cloudflares DDoS detection network.– I am unable to connect or publish to the broker. If I use my IP address it works fine and if I deselect the “orange cloud” then I can publish via domain name. This is because cloudflare doesnt allow requests from port 1883–and many other ports. They do allow web socket ports however. So maybe if I have a IoT device it can use an encrypted mqtt port and when I use MQTT in the browser I can use the WSS protocol.

        This cloudflare developer tutorials link outlines the process, and beneath it they have a tutorial to provision these certs to IoT devices and a mobile app(however, the IoT uses https) — https://developers.cloudflare.com/ssl/client-certificates/create-a-client-certificate

        1. Hi
          I looked at it and I think that you can generate client certs etc and use it over websockets with the broker set up as an origin server.
          Using mqtt and ssl isn’t possible as I see it.
          Is there a reason yo use cloudflare. Will you have many websocket connections?

          1. Hi Steve. Sorry for this. I reached out to cloudflare and asked the maintainers of mosquito- the problem boils down to the fact that I don’t have access to the root certificates/certificate chain for cloudflare which won’t make using these certificates possible. I tried to use cloudflare because they can generate free client certificates. I’ve changed my approach to my problem though. Sorry if I wasted any of your time. You’re tutorials are very helpful. Thanks again Steve.

          2. Yes I have used lets encrypt to secure a web server. I was told that I couldn’t use it to generate client certificates. I don’t know how I could adapt it to Mosquitto & groups of IoT devices. If know of any resources to learn how to do this that would be helpful.

          3. I will try to repeat the process in the tutorial using lets encrypt this week
            Rgds
            Steve

  23. Hey Steve,
    thx for the detailed guide!
    I have a problem with the require_certificate and use_identity_as_username parameter. When I set them up to true, I get the following message:

    Client x|y-commonname sending CONNECT
    Error: A TLS error occured.

    When I set them to false, the TLS connection works as expected (from my point of view).

    The mosquitto.conf looks in principle like:
    listener 8883
    tls_version tlsv1.2
    cafile /y/c/ca_certificates/ca.crt
    certfile /y/c/certs/server.crt
    keyfile /y/c/certs/server.key

    require_certificate true
    use_identity_as_username true

    Thank you very much!

    1. When you set them True the broker requires a certificate from the client. Have you configured those. The certificates need to use the same CA as the SSL connection
      Rgds
      Steve

  24. HI all,
    Thanks for such a great tutorial and explanation.
    After applying all this steps i am facing the issue with connection to mqtt broker.(on raspberry and Node RED)
    I also tried to change TLS version on broker side, but without help.

    Thanks in advance

    My mosquitto.conf
    per_listener_settings true
    pid_file /var/packages/mosquitto/target/var/mosquitto.pid
    port 1883
    cafile /volume1/@appstore/mosquitto/var/ca.crt
    certfile /volume1/@appstore/mosquitto/var/server.crt
    keyfile /volume1/@appstore/mosquitto/var/server.key
    listener 8883
    tls_version tlsv1.1
    require_certificate true
    use_identity_as_username true
    log_dest file /volume1/@appstore/mosquitto/var/mosquitto.log
    log_type error
    log_type warning
    log_type notice
    log_type information

    MQTT broker log from NAS synology
    Starting mosquitto command /volume1/@appstore/mosquitto/sbin/mosquitto -d -c /volume1/@appstore/mosquitto/var/mosquitto.conf
    1611316308: mosquitto version 1.6.12 starting
    1611316308: Config loaded from /volume1/@appstore/mosquitto/var/mosquitto.conf.
    1611316308: Opening websockets listen socket on port 8883.
    1611316308: Opening ipv4 listen socket on port 1883.
    1611316308: Opening ipv6 listen socket on port 1883.
    1611316308: mosquitto version 1.6.12 running
    1611317344: New connection from 192.168.1.161 on port 1883.
    1611317344: OpenSSL Error[0]: error:14209102:SSL routines:tls_early_post_process_client_hello:unsupported protocol
    1611317344: Socket error on client , disconnecting.
    1611317357: New connection from 192.168.1.161 on port 1883.
    1611317357: OpenSSL Error[0]: error:14209102:SSL routines:tls_early_post_process_client_hello:unsupported protocol
    1611317357: Socket error on client , disconnecting.

    The same problem also from Raspberry pi
    pi@raspberrypi:~/automatizacia/MQTT $ mosquitto_pub –tls-version tlsv1.1 –cafile ca.crt –cert client.crt –key client.key -d -h NAS.local -p 1883 -t test -m “hello there”
    Client mosqpub|4064-raspberryp sending CONNECT
    OpenSSL Error: error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version
    Error: A TLS error occurred.
    pi@raspberrypi:~/automatizacia/MQTT $ mosquitto_pub –cafile ca.crt –cert client.crt –key client.key -d -h NAS.local -p 8883 -t test -m “hello there”
    Client mosqpub|4065-raspberryp sending CONNECT
    OpenSSL Error: error:1408F10B:SSL routines:ssl3_get_record:wrong version number
    Error: A TLS error occurred.

    Node RED log running in docker on synology:
    AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36)
    22 Jan 13:09:54 – [info] [mqtt-broker:NAS] Connection failed to broker: mqtts://NAS.local:8883
    22 Jan 13:09:59 – [info] [server:Home Assistant] Connecting to http://supervisor/core
    22 Jan 13:09:59 – [info] [server:Home Assistant] Connected to http://supervisor/core
    22 Jan 13:10:09 – [info] [mqtt-broker:NAS] Connection failed to broker: mqtts://NAS.local:8883

    pi@raspberrypi:~/automatizacia/MQTT $ ping NAS.local
    PING NAS.local (192.168.1.153) 56(84) bytes of data.
    64 bytes from 192.168.1.153 (192.168.1.153): icmp_seq=1 ttl=64 time=1.61 ms
    64 bytes from 192.168.1.153 (192.168.1.153): icmp_seq=2 ttl=64 time=1.31 ms
    64 bytes from 192.168.1.153 (192.168.1.153): icmp_seq=3 ttl=64 time=2.20 ms

  25. Hi Steve,
    really need your help here. I am trying to make this work on Raspberry Pi 4, latest Raspbian image installed.
    I used your scripts to create the certs, but I cannot get things running.
    This is what I get
    ________________
    $ sudo mosquitto_pub –cafile ~/ssl/server-certs/ca.crt –cert ~/ssl/client-certs/client.crt –key ~/ssl/client-certs/client.key -d -h raspi00 -p 8883 -t test -m “hello there”
    Client mosq-eRqbfbeRA630w5Ho14 sending CONNECT
    Error: host name verification failed.
    OpenSSL Error[0]: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed
    Error: A TLS error occurred.
    ________________
    and in the mosquitto log I read
    _______________________
    New connection from 127.0.0.1 on port 8883.
    1609676639: OpenSSL Error[0]: error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error
    1609676639: Socket error on client , disconnecting.
    _______________________

    I have been banging my head for hours, with no luck.
    Have you got any hint/suggestuions on howto move forward to make this work?
    Thanks 🙂

    1. Hi
      It looks like the common name you used on the server certificate isn’t the same as the one you are using in the mosquitto_pub command which is raspi00.
      Use the –insecure switch if that works then it is a name mismatch
      rgds
      steve

      1. Thanks Steve,
        really appreciate your help. Yes, that’s right, I had to recreate the certificates so that the DN of the certificate for the server running Mosquitto is raspi00. That was the issue.
        Many thanks for your kind help again 🙂

  26. Hai,
    Thank you for the reply.
    And it is regardless of self signed certifcates or certificates signed by third party, right?

  27. Hi,
    I was doing few tests for secure MQTT using different certificates. Here is one of the test case which failed for me.
    * used client.crt which is signed by clientCa.crt in my Mqtt Client (mqttnet).
    * used server.crt which is signed by serverCa.crt in mosquitto broker.
    I imported clientCa.crt in trusted root certificate authorities in my server. But still it failed.
    It is given in this blog that “The client and server must use the same CA (certificate Authority) for the client and server certificates.”.
    Does it mean that if client and server does not use same CA, then the server can never authenicate the client certificate?

    Thank you
    Appu

  28. Hi, Steve thx for this post 🙂

    i have a problem here with my project, im using raspberry pi3b+ which has the broker and the publisher, my configuration for broker is:

    pid_file /var/run/mosquitto.pid
    listener 8883 192.168.1.106
    #allow_anonymous true
    connection_messages true
    include_dir /etc/mosquitto/conf.d
    cafile /etc/mosquitto/ca_certificates/mosquitto.org.crt
    keyfile /etc/mosquitto/certs/broker.key
    certfile /etc/mosquitto/certs/broker.crt
    tls_version tlsv1
    protocol mqtt
    #require_certificate true
    #use_identity_as_username true
    #password_file /etc/mosquitto/pwfile

    the publisher is in raspberry pi and the subscriber i want to run it in other machine with ubuntu, the code for the publisher that i use is this

    publish.single(‘BPM’,”%d” % BPM,hostname=’192.168.1.106′,port=8883,tls={‘ca_certs’:”/etc/mosquitto/ca_certificates/mosquitto.org.crt”})

    the subscriber has the next code:

    client.tls_set(ca_certs=”/etc/mosquitto/ca_certificates/mosquitto.org.crt”,certfile=”/home/pi/cliente_pi.crt”,keyfile=”/home/pi/cliente_pi.key”)

    client.connect(host=”192.168.1.106″,port=8883)

    i choose for CA certificate test.mosquitto.org and the same to sign client and server certificates, and its working good if all the scripts publisher and subscriber are in raspberry, good comunication with tls, but when i move the subscriber to other machine with ubuntu it produced this error:

    ssl.SSLCertVerificationError: [SSL: Certificate_verify_failed] IP address mismatch, certificate is not valid for ‘192.168.1.106’. (_ssl.c:1108)

    the curious thing is i tried mosquito_sub -h 192.168.1.106 -p 8883 –cafile /PATH -m “hello world” -t test
    and its working fine the message that i send from raspberry to other laptop with ubuntu it received properly, but when i tried to put the subcriber in script the error appear, i use python 2.7, i tried too with python 3.8 but the error continue appearing.

    i really apreciate some ideas to try 🙂

    Thx

    1. Hi
      Looks like a ca name mismatch try using in insecure option to verify this.
      You alos seem to be mixing publish with subscribe commands
      mosquito_sub -h 192.168.1.106 -p 8883 –cafile /PATH -m “hello world” -t test
      Assume was a typo.
      Also It looks line on the subscribe side you are using client certificates if so remove them and try juts using SSL
      Rgds
      Steve

  29. Hi Steve! nice post btw. I tried this and could not make it work.

    I created a CA key and cert, and also server key and cert and could enable a secure TLS connection, now using the same CA key and following this steps I’m getting the following errors:

    Client side: ssl3_read_bytes:tlsv1 alert unknown ca
    Server side: tls_process_client_certificate:certificate verify failed

    My .conf file has a listener defined as follows:

    # =================================================================
    # MQTT mutual-authentication
    # =================================================================
    listener 8884
    protocol mqtt
    capath /mosquitto/data/ca.crt
    keyfile /mosquitto/data/server.key
    certfile /mosquitto/data/server.crt
    require_certificate true

    —-
    I also tried using the use_identity_as_username flag

    any clues? thanks!

      1. Thanks for the quick reply.

        Indeed, I’ve used your scripts with the same result, I’m deploying everything to a docker container using the eclipse-mosquitto official image (latest version).

        I have also tried using the official documentation: https://mosquitto.org/man/mosquitto-tls-7.html and the problem remains.

        If you have any clues please let me know, I’ll keep on trying to make it work and if I’m successful with this I’ll post my results!

        Thanks again, and sorry for bothering you.

          1. tried in 2 different mac computers and having the same problem, where are you storing the broker certificates ? I’m using a fixed folder should I use some location inside /etc/ ? do you happen to have a full broker config with certificates to share?

            I’m using test.mosquitto.org to test it now, but would love to have something locally and not depend on any 3p.

            Thanks again,

          2. The best solution is to install a local mosquitto broker. If you don’t have one then I will configure one on my network and send you the can so you can test.
            Rgds
            Steve

  30. Hi, Thanks for the great article and tutorial.
    We’re using Mosquitto in an enterprise environment, and we are wanting to move to SSL encrypted traffic.
    We are using Active Directory and have our own domain-based CA.
    Is there a way to get Mosquitto broker to leverage somehow this infrastructure or integrate with it in some way ? All the tutorials are based on using OpenSSL to be ‘your own CA’ and self-sign, but we’ll be looking at managing up to 100 separate brokers and managing the certificates in this way will be an arduous task.
    Any pointers would be greatly appreciated !
    thanks

    1. David
      You can use any CA certificates on mosquitto so you can generate them in AD. However you can’t distribute them to mosquitto using Active directory.
      Take me back a bit as I used to train Active directory and windows 2000 but stopped in about 2003 so I guess it has moved on a lot since then.
      Rgds
      Steve

  31. Steve,

    This is a lot to take in and your guidance has helped, but there’s one tough challenge here: how to make a cert for a TLS connection when you’re just making clients and using someone else’s broker server. In my case that’s CloudMQTT, whose docs leave much to be desired:
    https://www.cloudmqtt.com/docs/faq.html#TLS_SSL

    Do I need their server cert (if I can get it) to make my client certs?

    Cordially,
    Dan

    1. Hi
      Interesting question and I will look into it. However Cloudmqtt don’t say that they support client certificates as far as I can see.
      Rgds
      Steve

  32. Hi Steve,

    Thanks for a great article.

    I am trying to figure out what happens in the following scenarios after a client (for example node-red) connects using client & server certificates and subscribes to a topic which they have read permission (controlled by acl_file).

    1. Client certificate is revoked or expires. Would the client be disconnected?
    2. Read permission on the topic removed for a user. Does a client for that user stop getting messages on that topic?

    Thanks.

    1. Hi
      There is no checking for revoked certificates so nothing would happen.
      For the ACL then the client would not longer receive messages on that topic.
      Rgds
      Steve

    1. I believe you can use a single client certificate for all clients but it isn’t recommended and so if you use client certificates then each client should have its own.

      1. I’m using “my-ca.crt” for connecting mqtt , and in mqtt.config file i gave “cafile /etc/mosquitto/certs/my-ca4.crt”. So for every certificate i generate should i also change the .config file?

        1. The config file on mosquitto stays the same. Each client needs to use it’s own client certificate there is no change needed on the broker other than to configure it to use SSL and client certificates.
          This is the relevant part of the file
          #ssl settings
          cafile /home/steve/mos/certs/ca.crt
          keyfile /home/steve/mos/certs/server.key
          certfile /home/steve/mos/certs/server.crt
          #client certifcate settings
          require_certificate true
          use_identity_as_username true

          Rgds
          Steve

  33. Hi Steve, Thanks for all this information. It has been most useful in the setup and configurations that I have used. There is one puzzle and I cannot get around it. The publishing client requires only Client certificate and key and doesn’t have a placeholder for the server certificate. Is there a way to have such a configuration. So if I use the command above as a template, instead of [[mosquitto_pub -h -p -t -m –cafile mqttproxy-ca.crt -u -P -d –cert mqttproxy-ca.crt –key mqttproxy-ca-pkcs8-withoutpass.key]], I have to use [[mosquitto_pub -h -p -t -m -u -P -d –cert mqttproxy-ca.crt –key mqttproxy-ca-pkcs8-withoutpass.key]]. I am using MQTT proxy for Confluent Kafka as the broker.

    1. Sorry
      Not sure what you mean as thee client doesn’t need to have a copy of the server certificate

  34. Hi Steve, you have been inspiritaion in many aspects, now I am securing all my devices . But I am facing an issue. mosquitto broker is working fine in user&pass , and TLS config on port 8883, tested from paho-eclipse websocket online app. So Iam 100% sure is working, also locally with this command : mosquitto_pub -h tatuiot.com -t test -m “hello again” -p 8883 –capath /etc/ssl/certs/ -u “” -P “” -d , but I am stuck with certificates. (I am using wildcard one for mosquitto broker) but which is the the one that mosquitto_pub is using from this path “/etc/ssl/certs/” I see 273 listed there. Thanks a lot in advance

    1. Hi
      It will use the one that corresponds to the CA on the broker as I understand it just the same way as when you access a website your don’t know the CA of the website so your browser has to search in the store for a matching one.
      Rgds
      Steve

    1. Yes I’m sure it is but I don’t have the time to do that at the moment if yoy develop one let me know
      rgds
      steve

  35. Hi Steve, I setup my mosquitto-tls following your tutorials.
    CA :
    openssl genrsa -des3 -out ca.key 2048
    openssl req -new -x509 -days 1826 -key ca.key -out ca.crt
    Common Name (eg, fully qualified host name) []:test.domain.com

    Server :
    openssl genrsa -out server.key 2048
    openssl req -new -out server.csr -key server.key
    Common Name (eg, fully qualified host name) []:mosquitto.test.domain.com
    openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 360

    Client :
    openssl genrsa -out client.key 2048
    openssl req -new -out client.csr -key client.key
    Common Name (eg, fully qualified host name) []:device1
    openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 360

    mosquitto.conf :
    port 1883
    listener 8883
    cafile /mosquitto/certs/ca.crt
    certfile /mosquitto/certs/server.crt
    keyfile /mosquitto/certs/server.key
    tls_version tlsv1.2
    use_identity_as_username true

    I use MQTT.fx to connect to my broker using ca.crt, client.crt, client.key. But getting following error

    2020-03-30 12:13:09,793 ERROR — MqttFX ClientModel : Error when connecting
    java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
    at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:217) ~[?:1.8.0_181]
    at java.security.KeyFactory.generatePrivate(KeyFactory.java:372) ~[?:1.8.0_181]

    at java.lang.Thread.run(Thread.java:748) [?:1.8.0_181]
    Caused by: java.security.InvalidKeyException: invalid key format
    at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:331) ~[?:1.8.0_181]

    2020-03-30 12:13:09,796 ERROR — MqttFX ClientModel : Please verify your Settings (e.g. Broker Address, Broker Port & Client ID) and the user credentials!
    java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format

    at java.lang.Thread.run(Thread.java:748) [?:1.8.0_181]
    Caused by: java.security.InvalidKeyException: invalid key format
    at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:331) ~[?:1.8.0_181]

    Any idea what is wrong with my setup ?

    1. No I have used MQTT.fx.
      I would go back a step and try it first just using SSL and no client certificates and get that working after that introduce the client certificates.
      If you get nowhere then use the ask steve page and get it touch and you can then send me your certs and keys and I will try them. I can also send you a python script to try.
      Rgds
      Steve

      1. I have two ports 1883 & 8883. I was able to connect to port 1883 with no SSL/TLS. Getting above error when I try to connect to port 8883 with SSL/TLS.

        1. Roy
          Have you tried just using SSL and note client certificates. Also have you tried the mosquitto_pub tool. It is also worth trying another machine in case there is a problem with the SSL version.
          Send me your certs and keys and I’ll try them.
          Rgds
          Steve

  36. Hi there,

    Anyone has configured successfully the client certificate for homeassistant mqtt?
    I am using a mosquitto broker and hass version 0.105.2.
    This is the message I get:
    Invalid config for [mqtt]: not a file for dictionary value @ data[‘mqtt’][‘client_key’]. Got ‘client.key’.

    with this configuration.yaml:
    mqtt:
    broker:
    port: 8883
    certificate: /etc/mosquitto/ca_certificates/ca.crt
    client_key: client.key
    client_cert: /etc/mosquitto/certs/client.crt
    tls_version: ‘auto’
    # tls_insecure: true
    # username: hass.client

    It is working perfectly when I am subscribing and publishing with mosquitto clients, from ubuntu.
    In the broker I have enabled the “require_certificate” option.
    But given the error, I guess the mqtt module from hass seems not to accept key file format or similar issue.
    I have already tried to change the permissions, and the issues remains…
    Any idea?

    Thanks a lot!
    jaeg89

    1. Already fixed. It was an issue with the read permissions of the key. I change them once, but I regenerate the key… Stupid me 🙂
      Thanks!

    2. Hello jaeg89, steve
      I am trying to configure mqtt in homeassistant and I have some problems.
      My broker works perfectly with another client developed in C++ and also with subscribing/publishing mosquito clients.
      I am not able to add configuration in configuration.yaml as everything seems to configured in GUI.
      In this GUI I tried to add the ca.crt, client.key and client.crt but its raised to following error: connection error.
      The log of mosquito broker are:
      692104960: New connection from 127.0.0.1:45377 on port 8883.
      1692104960: OpenSSL Error[0]: error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate
      1692104960: Client disconnected: Protocol error.

      Could you please help me please?

      Thanks for your precious help.

      Matthieu

      1. It looks like you are trying to use client certificates is that the case? Have you tried it with ssl only?
        rgds
        steve

        1. Hello Steve,
          Many thanks for your quick reply. I really appreciate.

          What do you mean by “with ssl only”?
          In home assistant I have the possibility to check the option “ignore validation of broker certificate”. Is it what you mean?

          Regards.

          1. When you configure a client you normally only need to have the CA on the client. In this mode you get a secure SSL connection just like on a web page.
            The validate server option in basically a check on the name you use to access the broker e.g test.mosquitto.org and the common name configured on the server certificate which should match.
            If you click ignore validation and it works then you have a name mismatch which is a common error.

            Client certificates can be used in place or username/password authentication in which case you need to install them on the client as well as the CA.
            Th mosquitto.con file has an entry that forces the client to provide these

            #client certifcate settings
            require_certificate true
            use_identity_as_username true

            Does that make sense?
            Rgds
            Steve

          2. Hi Steve,
            Thanks again for your explanation. It helps me a lot.
            Nevertheless, I don’t understand the behavior of HomeAssistant.
            As I can’t post a screenshot, you can find below the list of the settings of MQTT integration:
            – Broker: I put the hostname of my rasberrypi
            – Port: 8883
            – Username: nothing for me
            – Password: nothing for me
            – Client ID: nothing for me
            – Keep Alive Time: 60s by default
            – Use Client Certificate (boolean)
            –> Client Certificate file
            –> Private Key file
            – Validation of the broker certificate (deactivated / auto / personalized)
            –> Autority Certificate file
            – Ignore the validation of broker certificate
            – MQTT protocole: I put 5
            – MQTT transport: TCP by default

            So I played with client and broker certificates.
            I generated the following files from your tutorials:
            server.crt, server.csr, server.key, ca.crt, client.crt, client.csr, client.key
            Here are the results of my tests:
            TEST 1:
            – Use Client Certificate: TRUE
            –> Client Certificate file: client.crt
            –> Private Key file: client.key
            – Validation of the broker certificate (personalized)
            –> Autority Certificate file: ca.crt
            – Ignore the validation of broker certificate: FALSE
            ====> CONNECTION ECHEC
            TEST 2:
            – Use Client Certificate: FALSE
            – Validation of the broker certificate (personalized)
            –> Autority Certificate file: ca.crt
            – Ignore the validation of broker certificate: FALSE
            ====> CONNECTION ECHEC
            TEST 4 and 5:
            Same as TEST 1 and 2 with:
            – Ignore the validation of broker certificate: TRUE
            ====> CONNECTION OK

            The good thing is that if I put a wrong ca.crt file (edit by hand), the GUI raises the error “The CA certificate is not valid”.

            So I don’t really understand why I can’t use my Client certificate.

            Does my tests 4+5 mean that my connection is secured all the same?

            How do you interpret the behavior of my tests?

            Thanks.
            Matthieu

          3. Test 4 and 5 work means that the connection is secure but there is mismatch in the name you used to create the server certificate and the name of the broker.
            You shouldn’t need any client certificates unless the broker forces them and I don’t Know why you would want that.
            If you access the broker using the ip address then the common name on the server certificate should be the IP address.
            Rgds
            Steve

          4. I thought that using a Client certificate will be safer. I was wrong!
            So thanks to your comments, my connection is safe. It is the main thing.
            What do you mean by “name of the broker”. I access to it thanks to the hostname of the raspberry where the broker is installed and I put exactly this hostname as “common name” when I created all the certificates.
            Anyway, it works, that’s fine 😉
            Thanks again.

  37. Hi Steve,

    Thanks for the great article! Helped me immensely. The client I am using requests only the CA certificate (ca.crt) and the client certificate (client.crt) and doesn’t ask for the client key (client.key). Should this be possible? It is asking for the certificates in DER format so I have converted them using openSSL but the system still doesn’t work. Other clients I have set up using MQTT.fx have worked OK when using the PEM formatted certs and keys is all good, however when using the DER formatted keys etc Mosquitto reports the following when trying to connect (same message when using either client):

    1580938430: New connection from 192.168.0.59 on port 8883.
    1580938430: OpenSSL Error: error:1417C0C7:SSL routines:tls_process_client_certificate:peer did not return a certificate
    1580938430: Socket error on client , disconnecting.

    Can you shed any light on this? Do I need to create all keys (not just client) in the DER format?

    1. Hi
      As far a I understand it you need the client key the format shouldn’t matter. If you use the ask steve page to contact me then you can send me all of the files (sever and client) by email and I’ll try them on my broker.
      Rgds
      Steve

  38. Hi, Steve
    Good article!
    I have setup mutual authentication with following configurations and they works well for my client using MQTT.fx.

    port 1883
    allow_anonymous false
    require_certificate true
    use_identity_as_username true
    cafile ~/root.crt
    certfile ~/server.crt
    keyfile ~/server.key

    The question is I do not see mosquitto server have a configuration method can check whether the client’s CN is in a local database for allowing connection. As you can see I already set allow_anonymous to false, although the client is signed by the CA certificate, it is still a unknown client to me when it is not in the ‘database’.
    The acl_file can limit the Pub/Sub permission of a specific username, but it can’t deny a client not in list.

    1. Just to clarify.
      You are trying tp limit access using certificate common name?
      Can you send me the acl you are using and I’ll try it.

      1. I did not build a ACL file. After checked ACL file syntax, it looks like it only be used to limit read/write permission to topics. It should be easy to define a ACL to not allow a user to pub/sub to any topic. But I want that user to be refused during connection. By checking it’s username (CN, as I defined use_identity_as_username)

        1. Hi
          It looks to me that the client name can be used for ACL control but not authentication as the certificate is doing that job.
          It is something I haven’t checked but reading the config file data seems to indicate that.
          rgds
          steve

  39. Hi Steve,

    Thank you for this wonderful article. I’m trying to achieve the same flow using Nginx as a load balancer and HiveMQ enterprise MQTT broker. The point is to Terminate SSL at the load balancer and also use client certificates for authentication. But the problem I’m facing is that the client certificates, even when changing the name of the client, works. Nginx authenticates the client irrespective of what the client ID is. Am I correct in assuming that this shouldn’t be the case? Only a client whose ClientID matches the FQDN string passed during its certificate creation be authenticated?

    1. Sorry but I’ve never used nginx with MQTT. However I suspect that nginx doesn’t cat about the client certificates as the authentication should be done on the broker.
      rgds
      steve

  40. Hi Steve,
    Very well explained!!
    I have a question,
    ca.crt – The Certificate authority certificate
    client.crt – The client certifcate file
    client.key – The client private key
    While publishing a message, we are using below:
    client.tls_set(‘c:/ssl/ca.crt’,’c:/ssl/client.crt’,\
    ‘c:/ssl/client.key’)

    Why should we send private key (client.key) in the handshake? That is to be stored securely right?
    Can you pls explain me in detail.

    Also We have an assignment:
    We are creating self-signed certificates using “openssl rsa” in the middleware(in our project). We’ve generated a cafile, certfile and privatekey and assigned it to vernemq broker(hosted in a cloud platform).

    Later we created multiple clients, each client is assigned a certfile and private key. Anyways cafile would be the same. Now these clients need to publish messages to the broker.
    We have configured in the message broker config file as below:
    listener.ssl.require_certificate=on and listener.ssl.use_identity_as_username=on

    How can the clients publish messages to the broker using their client certificates and how would the broker validate if it is a valid client? How can we do asymmetric key encryption?
    Can u pls describe any approach for this?

    Thanks in advance.

      1. Hi Steve,
        I have a question.
        I’m using a vernemq message broker. I have a client in VM which is trying to connect to the message broker using certificates. (Self-signed).
        I used the same CA in generating certificates for both the message broker and the client.
        CN for Vernemq message broker is “message broker”
        CN for client in VM is “send-data”
        client is written in nestjs( nodejs framework)
        Now, when i try to make a connection from the client to the message broker.

        It says “Error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate’s altnames: Host: vmq.services. is not cert’s CN: messagebroker”

        Any idea? Why am i getting this error and how to resolve it?

        Thanks,
        Sri Durga

        1. I can only assume that the certificate common name doesn’t match the name that is being used by the server it is being used on. Most clients have an insecure option which bypasses this check. If that works then it more or less proves the name/IP mismatch.
          rgds
          steve

  41. Hi Steve.
    First of all thank you for all of these information, but I want to know what is the purpose of these client step. What will happen if we use only ca.crt but not client.crt and client.key? Thank you in advance…

    1. Using the ca.crt only on the client is the way most clients will be configured. This mode is effectively the same mode as you use on a web browser when accessing a secure site.
      You only need client certificates if you want to use them to authenticate the client usually in place of a username/password authentication.
      DEoes that make sense?
      Rgds
      Steve

      1. Thank you for a quick response 🙂
        Now. I am trying to use client certificate but I am facing with the error:
        ssl.SSLError: [SSL: TLSV1_ALERT_UNKNOWN_CA] tlsv1 alert unknown ca (_ssl.c:661)
        when I try to connect. What can be the reason of this ? Btw
        my tls_set code is —-
        client.tls_set(‘/home/pi/Security/ca.crt’,’/home/pi/Security/client1.crt’,’/home/pi/Security/client1.key’)
        Is there any error here?
        Thx in advance again …

        1. Hi
          Looks ok. Did you try just using the ca.crt file. Can you show me the mosquitto.conf file for this.
          Rgds
          Steve

          1. My original conf file is like :
            port 1883
            listener 8883
            cafile /home/pi/Security/ca.crt
            keyfile /home/pi/Security/server.key
            certfile /home/pi/Security/server.crt

            I’m sorry for deleting by mistake.

          2. You also need these lines when using client certificates
            #client certifcate settings
            require_certificate true
            use_identity_as_username true
            rgds
            steve

        2. Hi Steve,
          Thanks for this awesome blog post!
          I am facing one challenge… I have a device certificate (device.pem) ,(devicekey.key) and secret key from the available device in cloud but I am confused which certificate do I need to use in tls_set().
          I have tried with eclipse paho tool and I have used cacerts (available in jre folder) with password “changeit” and devicekey.key as keystore and device secret as password.
          Please help and let me know if any other information is required.
          Thanks,
          Sunny

          1. Hi
            You need the Ca certificate the client certificate and the client key
            example

            client.tls_set(‘c:/ssl/ca.crt’,’c:/ssl/client.crt’,\
            ‘c:/ssl/client.key’)
            Rgds
            steve

          2. Hi Steve,
            Thanks for the help.
            I have provided all the certificates (ca.crt, client.crt, client.key) in tls_set but when I am trying to execute client.connect(broker,8883,timeout) I am getting [SSL:CERTIFICATE_VERIFY_FAILED] certificate verify failed : unable to get local issuer certificate (_ssl.c:1056)
            Trace back: selfobj.do_handshake()

            Please help !

            Thanks,
            Sunny

          3. This is usually caused by the common name on the server certificate being different to the name you use when you access the broker. If you use the insecure option in the client then it overrides the check and it should work. If it does then it is a clear sign that you have a name mismatch
            rgds
            steve

          4. Hi Steve,
            Thanks for the reply!
            Please help me in solving my confusion. What will be the use of the device certificate then if i will be using the certificated generated by me using openssl?
            I tried with the “MQTT.fx” and enabled “TLS/SSL” and “selected self sign certificates in keystore” option.
            my keystore file : cacerts -> got from jre folder where java is installed
            client keystore file : client.key
            client keystore is generated by “openssl pkcs12 -export -in certificate.pem -inkey certificate.pem -out client.ks”
            client keystore password : password from device certificate (generated automatically )
            client keypair password : same as client keystore password.

            so my confusion is what will be the values in tls_set parameter() ?

            Thanks for the help!

          5. Hi
            Client certificates are used instead of username/password authentication.
            Client certificates are considered more secure than username/password encryption but they are more difficult to set up and less well understood.
            However they need an encrypted connection to work and therefore the connection must use SSL.
            Does that make sense
            rgds
            steve

Leave a Reply to Appu Cancel reply

Your email address will not be published. Required fields are marked *