This is a cache of https://developer.ibm.com/tutorials/mq-secure-msgs-tls/. It is a snapshot of the page as it appeared on 2026-02-09T22:25:25.553+0000.
Secure communication between IBM MQ endpoints with TLS
IBM Developer

Tutorial

Secure communication between IBM MQ endpoints with TLS

Protect your messages by encrypting connections

By Richard J. Coppen, Max Kahan, Stuti Uniyal

In other tutorials (the "Ready, set, connect" series and "Write and run your first IBM MQ Jakarta application") we showed you how to set up and use point-to-point messaging between a JAKARTA application and an MQ server. In these tutorials, the communication between the client and the server that flows over the internet was not encrypted. This meant that the contents of the message travelled in plain text and could have been viewed by a third party.

This tutorial will get you started with securing messages in transit through the use of Transport Layer Security (TLS) for MQ.

It's important to note that the default developer configuration that is used in the other Ready, set, connect tutorials includes authentication and authorization controls for the app and admin users.

TLS is a cryptographic encryption protocol that protects data in transit. See Figure 1 for an explanation of how the TLS handshake between a client and a server works:

Figure 1: A TLS handshake

Graphic showing a TLS handshake

In Figure 1:

  1. The server and client communicate to establish connection settings.
  2. The client verifies the server certificate.
  3. The client generates a cipher and encrypts it using the server’s public key. This is shared with the server and used to generate a symmetric key to encrypt the remainder of the session.

TLS authentication methods include anonymous and mutual authentication.

In this tutorial, we will set up the simplest configuration, in which we provide a certificate to the server side only.

How does TLS work in IBM MQ?

TLS is used in MQ to secure channels. It provides both integrity and encryption protection. When a channel is enabled for TLS, any messages that are passed by the channel will be protected while in transit. You can learn more about TLS in the IBM MQ documentation.

In a production environment, the queue manager will usually have a digital certificate issued by a certificate authority. Your MQ administrator should provide any certificates that you might need to use with your client application.

In this tutorial, we will be creating a self-signed certificate and extracting the public key from it for the client to use. A self-signed certificate is signed with its own private key; that is, “I am trustworthy because I say so.” It should not be used in a production environment, but it is useful in this example to understand how the TLS configuration works.

To demonstrate the basic MQ TLS configuration, we will use the IBM MQ Container image to run an MQ server in a container. We could run the server wherever we like, but the MQ container makes it easy to configure security from an MQ administration perspective.

Prerequisites

Steps

These are the steps we’ll go through to set up TLS:

  1. Create TLS objects: Use OpenSSL to create the TLS objects, a self-signed server key and certificate. Then, create a client keystore to store a copy of the server certificate on the client side, so the client knows it can trust the server
  2. Set up the MQ server: Start an MQ queue manager (our server) running in a container which is set up for TLS encrypted messages
  3. Secure an application: Edit some sample code to enable it to send encrypted messages to the queue manager

Step 1. Create TLS objects

We need to create a server key and certificate. Then, we need to create a client keystore, either using JAKARTA or other MQ client libraries.

Create a server key and certificate

To create the certificates we need to secure our channel, we will use OpenSSL, which is installed by default on most machines. Check if you have OpenSSL installed by entering this command in your terminal:

openssl version

If you need OpenSSL, you can download it.

Create a new directory on your machine and navigate into it in your terminal.

Now we can create the server key and certificate with this command:

openssl req -newkey rsa:2048 -nodes -keyout key.key -x509 -days 365 -out key.crt

You will be prompted to enter some information. Put whatever you like, as it is a self-signed certificate and is meant for your eyes only. Verify that the certificate has been created successfully with this command:

openssl x509 -text -noout -in key.crt

You should see the information you entered and other certificate properties such as the public key and the signature algorithm.

Create a client keystore

The instructions for creating a client keystore differ slightly for Java code using the JAKARTA API and code in other languages that use the MQ Client Libraries (such as C, Python, Node.js, or Golang).

Follow the next set of steps that follow based on your language.

Creating a JAKARTA keystore (Java)

For our example, we will be securing some Java code written for JAKARTA. We will use keytool (a Java security tool), which is included with Java JREs and SDKs. To create a .jks client keystore and import our sever certificate into it, enter:

keytool -keystore clientkey.jks -storetype jks -importcert -file key.crt -alias server-certificate

You will be prompted to create a password. Be sure to remember the password that you set as you'll need it later on.

Listing the contents of the directory should yield something like this:

Output of the keytool command

Move the clientkey.jks file into a new folder in a different directory that you will remember. A good idea is to create a new folder in the root directory of your client application and put the .jks file there.

Now you should have only the .crt file and the .key file in your current directory. If this is not the case, the container will not work! You'll need to return to the beginning of step 1 and check that you completed all the tasks so that these files are in the right place.

Creating a keystore for MQI-based client applications (C, Python, Node.js, Golang)

If you’re using MQI, whatever language you write your application in (such as C, Python, Node.js, or Golang), these steps will help you create a client keystore and import our server certificate into it.

If you don’t have the MQ client libraries installed, it’s time to get them:

  • For macOS, follow the steps in the MQ macOS Toolkit tutorial, paying special consideration for ARM-based MacOS machines.

  • For Windows or Linux MQ clients, download and install one from the IBM Support site.

Now that you have the MQ client libraries, you’ll have the MQ security command line tool, runmqakm. Enter this command to create a keystore in .kdb format and store the password in a .sth file.

Remember to substitute [!!pick_a_passw0rd_here!!] for a password of your choosing.

runmqakm -keydb -create -db clientkey.kdb -pw [!!pick_a_passw0rd_here!!] -type pkcs12 -expire 1000 -stash

We have generated a stash file that contains the keystore password to simplify the following steps. If you prefer to enter the keystore password manually, then remove the -stash option from the command and be sure to remember the password you set!

Next, import the server’s public key certificate into the client keystore by entering this command:

runmqakm -cert -add -label QM1.cert -db clientkey.kdb -stashed -trust enable -file key.crt

If you list the contents of the current directory, you should see these files:

Output of the keytool command

Move the clientkey.kdb and clientkey.sth files into a new folder in a different directory that you will remember. A good idea is to create a new folder in the root directory of your client application and put the files there.

Now you should have only the .crt file and the .key file in your current directory. If this is not the case, the container will not work! You'll need to return to the beginning of step 1 and check that you completed all the tasks so that these files are in the right place.

Step 2. Set up the MQ server

Our first step in setting up the MQ server is to start Docker or Podman.

If you completed the "Get an IBM MQ queue for development in a container" tutorial, you installed either Docker or Podman in Step 1, and you installed MQ as a container image in Step 2. If you did not complete this tutorial, complete step 1 and step 2 in that tutorial before proceeding ahead.

You are now ready to run a container from the latest MQ Container image. If you completed the "Get an IBM MQ queue for development in a container" tutorial, you will need to stop this container by using the podman stop <container_id> command, or you need to select different ports to map to on your host OS.

We will run a series of commands to start the latest MQ Container

These commands create a volume which will be mounted to a specific directory of the container. We will copy the private key (.key) and public certificate (.crt) for the queue manager, to this directory in the container. These will remain on the volume even when the container is removed.

The first command creates a container named mqtls but doesn’t start it. It also creates a volume named tls-key-vol and mounts it onto the container. In this example, we used the password passw0rd for the app user, but you should specify the one you used previously (the one set during the “Get an IBM MQ queue for development in a container” tutorial).

With Podman:

podman create -it --name mqtls --env LICENSE=accept --env MQ_QMGR_NAME=QM1 --mount="type=volume,src=tls-key-vol,dst=/etc/mqm/pki/keys/mykey" --publish 1414:1414 --publish 9443:9443 --env MQ_ADMIN_PASSWORD=passw0rd --env MQ_APP_PASSWORD=passw0rd icr.io/ibm-messaging/mq:latest

With Docker:

docker create -it --name mqtls --env LICENSE=accept --env MQ_QMGR_NAME=QM1 --mount="type=volume,src=tls-key-vol,dst=/etc/mqm/pki/keys/mykey" --publish 1414:1414 --publish 9443:9443 --env MQ_ADMIN_PASSWORD=passw0rd --env MQ_APP_PASSWORD=passw0rd icr.io/ibm-messaging/mq:latest

Next, specify the full path to the local directory that contains your .key and .crt files and copy the files over to the directory in the container with the following command.

With Podman:

podman cp -a [!!path to directory with key and crt files!!]/. mqtls:/etc/mqm/pki/keys/mykey

With Docker:

docker cp [!!path to directory with key and crt files!!]/. mqtls:/etc/mqm/pki/keys/mykey

Now, start the container.

With Podman:

podman start mqtls

With Docker:

docker start mqtls

Note: If you're using Windows in Hyper-V mode, you might have to add the directory with the .key and .crt files to file sharing in your Docker settings or Control Panel, or Docker might not be able to access it.

Enter the following command to see the container ID.

With Podman:

podman ps

With Docker:

docker ps

You should see output similar to this:

Output from docker ps command

Be sure to make a note of your container ID as you will need this later on.

Verify that security has been enabled

Let’s have a look at the queue manager to check that security has been enabled. Exec into the container with this command.

With Podman:

podman exec -it mqtls bash

With Docker:

docker exec -it mqtls bash

Then, enter this command:

runmqsc QM1

This command allows you to use the MQSC interface for the queue manager. Find out about channel properties by entering this command:

DISPLAY CHANNEL(DEV.APP.SVRCONN)

You’ll see output similar to:

Output about the channel properties

We see that the SSLCIPH option has been configured to use the ANY_TLS12_OR_HIGHER CipherSpec. When the SSLCIPH option is set, it turns on TLS encryption for any connections to the queue manager using this channel.

In this tutorial, we use anonymous (server-only) authentication, as we authenticate the client with the application name and password.

Figure 2: TLS authentication methods

Graphic showing TLS authentication methods

In Figure 2:

  1. Anonymous authentication: The server provides a certificate to the client.
  2. Mutual authentication: Both the server and the client provide a certificate and authenticate each other.

We will need to specify a compatible CipherSpec on the client side for the client and server to be able to connect and carry out the TLS handshake.

Exit the MQSC interface with exit, and exit the container with exit too.

Step 3. Secure an application

The instructions for securing an application differ slightly for JAKARTA applications and MQI client applications (such as C, Python, Node.js, or Golang). Follow the set of steps based on your language.

Secure and run a JAKARTA application (Java)

After getting the JAKARTA application up & running, you'll need to encrypt it and run it.

Get a JAKARTA application up and running

First, follow the steps in the "Write and run your first IBM MQ JAKARTA application" to get up and running with a JAKARTA sample application, JakartaPutGet.java. Make sure that you have the hostname and port number set up to match the details of your new TLS-enabled container.

Run a JAKARTA application without encryption

Let’s see what happens if we try to connect to the queue manager without encryption on the client side.

From your top level application directory (MQClient if you’ve followed the JAKARTA tutorial) compile the application with

javac -cp ./com.ibm.mq.jakarta.client-9.4.2.0.jar:./jakarta.jms-api-3.1.0.jar:./json-20250107.jar:. com/ibm/mq/samples/jakarta/JakartaPutGet.java

and run with

java -cp ./com.ibm.mq.jakarta.client-9.4.2.0.jar:./jakarta.jms-api-3.1.0.jar:./json-20250107.jar:. com.ibm.mq.samples.jakarta.JakartaPutGet

The connection is rejected by the queue manager, with a lot of errors. You’ll see an MQRC_JSSE_ERROR, as well as a Remote CipherSpec error for channel DEV.APP.SVRCONN as we didn’t specify an encryption cipher on the client side. The stack will have parts that look like this:

Output of running JAKARTA application

If your failed with a different error, try our handy cheatsheet to help you debug the error.

Encrypt the JAKARTA application

Let’s add encryption to the client application. We’ll choose a specific ANY_TLS12_OR_HIGHER-compatible CipherSpec but you can also set the spec to be *TLS12. Edit the JakartaPutGet.java sample to add this line underneath the other connection factory properties

cf.setStringProperty(WMQConstants.WMQ_SSL_CIPHER_SUITE, "TLS_AES_256_GCM_SHA384");

Compile as above. When running, use this command, which includes setting some environment variables. You'll need to edit the command before you run it to add in the fully qualified name of your trust store and its password.

java -Dcom.ibm.mq.cfg.useIBMCipherMappings=false -Djavax.net.ssl.trustStoreType=jks -Djavax.net.ssl.trustStore=/your_key_directory_path/clientkey.jks -Djavax.net.ssl.trustStorePassword= [the_password_that_you_set] -cp ./com.ibm.mq.jakarta.client-9.4.2.0.jar:./jakarta.jms-api-3.1.0.jar:./json-20250107.jar:. com.ibm.mq.samples.jakarta.JakartaPutGet

Success! You will see something like:

Output from running an encrypted JAKARTA app

Note: the -Dcom.ibm.mq.cfg.useIBMCipherMappings=false argument in the run command was necessary as we are using a non-IBM JRE. If you want to use an IBM JRE, simply remove this argument.

When there is a mismatch between cipherMappings and JRE , then you will get the following error:

Error Output from JAKARTA app

Secure and run an MQI application (C, Python, Node.js, or Golang)

For this tutorial, we’re only showing an example in one language: Python. For high-quality sample code securing other languages, have a look here. We’re assuming you have a Python installation and are in a Python environment where you’re happy to develop MQ applications.

Get a python application up and running

The MQ client functionality is implemented in Python with PyMQI, which is an open-source Python wrapper over the MQ client. Installing it is as easy as typing the following command in your terminal:

pip install pymqi

Let’s try and connect to an encrypted channel and send a message using an unencrypted Python program. Use the below given command to get the python application.

curl -o sample.py https://raw.githubusercontent.com/ibm-messaging/mq-dev-samples/refs/heads/master/gettingStarted/python/sample.py
Run a python application without encryption

Now we have our Python application, run it with this command:

python sample.py

The connection will be rejected by the queue manager, and you will see an error message as part of the returned output:

Output from running non-encrypted python application

This is because our unencrypted Python application tried to connect to an encrypted channel, which throws the error above.

Encrypt the python application

Let’s add encryption to our client application. We’ll choose a specific ANY_TLS12_OR_HIGHER-compatible CipherSpec, but you could also set the spec to be ANY_TLS12.

Edit the Python file you downloaded and uncomment the following lines:

# cd.SSLCipherSpec = b'TLS_AES_256_GCM_SHA384'
# sco = pymqi.SCO()
# sco.KeyRepository = b'[!!your_keystore_location here!!]' # include file name but not file extension

Remember to substitute [!!your_keystore_location here!!] with the correct path of your keystore file.

Add the sco variable into your connect_with_options function like this:

qmgr.connect_with_options(queue_manager, user='app', password='[!!password for user "app"!!]', cd=cd, sco=sco)

Run your application again, and you should see:

Output of running encrypted python app

Summary and next steps

Congratulations! You configured basic TLS for MQ so the queue manager and the client application can now encrypt their communication as it flows over the internet. You used OpenSSL to create a self-signed digital certificate for the queue manager. This enabled the client and the server to negotiate a shared secret key to encrypt their session.

You should now understand what needs to be configured on the MQ server and the client application side, to use TLS with MQ. You have enabled the client and the server to communicate privately and securely using a self-signed certificate. Remember to upgrade to a real certificate before you put your apps into production!

To see production-style samples with encryption and logging enabled, visit our IBM Messaging GitHub repository.