Setting up TLS in Db2 may seem like a daunting task but it doesn’t have to be.
The use of Transport Layer Security (TLS), the industry standard for the encryption of data in transit, has exploded over the past decade. Db2 has supported TLS for a long time now, with TLS 1.2 and TLS 1.3 being the currently supported versions. All it takes are a few extra steps, and your database and applications will be securely talking on the network.
In this first part of a series of blogs, we will break down common TLS scenarios you may encounter with Db2, potential mistakes that can be made, and how you as a database administrator can resolve them. While we will briefly summarize important TLS concepts throughout this series, some basic familiarity with these concepts is expected.
Without further delay, let’s get right into setting up TLS on our server for the first time.
Configuration of the Db2 server
Configuring the Db2 server for TLS is done at the instance level using the database manager configuration (DBM cfg) and the DB2COMM registry variable. Specifically, the following DBM cfg parameters are relevant to the configuration:
SSL_SVR_KEYDB: defines the path to the keystore used by the server to store the TLS certificate.
SSL_SVR_STASH: defines the path to the stash file used for SSL setup.
SSL_SVR_LABEL: defines the label for the SSL certificate in the keystore.
SSL_SVCENAME: defines the SSL service name or port number.
You may not be familiar with some of the key concepts such as keystores or stash files mentioned above, so let’s take a look at this before setting these parameters up.
Keystore and Stash Files
TLS uses objects called certificates, which serve to represent the identity of your server during the TLS handshake. The handshake is a negotiation process to establish a secure session between the client and the server. Certificates are stored in a keystore. TLS keystores for Db2 are usually created using GSKit, an IBM cryptographic and key management provider. To create a keystore, use the following command:
gsk8capicmd_64 –keydb –create –db /home/db2inst1/server.p12 -pw <password> -stash
This command will create a keystore at /home/db2inst1/server.p12. If a path is not given, the keystore is created in the current directory. The keystore needs to be in a location that is accessible by the instance owner and protected from unintended overwrites. For example, the instance owner’s home directory is a good place for this. In contrast, the instance directory is not a good place for this, since the instance directory is often recreated during an upgrade. Note the full path to your keystore for later.
The format of the keystore depends on the extension you provided on the command, which will be “.p12” for a PKCS12 keystore, or “.kdb” for a KDB keystore. Alternatively, you can use the “-type” option to provide the keystore format. We recommend PKCS12 keystores – they're easier to work with and if you run into trouble, they are compatible with a wider variety of tools such as OpenSSL compared to KDB keystores, which is an IBM proprietary format.
You may have noticed that we provided a “-stash” option in our command. This option creates a stash file for our keystore, which is a binary blob file that effectively represents our provided password. Db2 will use this file to automatically open the keystore. Otherwise, you’d have to provide the keystore’s password every single time the keystore is accessed... which can be a lot! In later commands to use and access the keystore, we will supply the “–stashed” option on subsequent gsk8capicmd_64 commands so we don’t have to type in our password. This file is created in the same directory as our keystore with the same name as our keystore, but with “.sth” as the file extension. In our case, our stash file would be at /home/db2inst1/server.sth. As before, note the full path to the stash file for later.
Your keystore will contain the certificates used for TLS, so remember to back it up. Also remember your stash file whenever you back up your keystore!
On Windows, Db2 supports using the native Microsoft Certificate Store. If you choose to use this, you will not have to create a keystore and stash file. You can refer to our documentation for further information about this option.
There are two other things we need: the certificate that will represent our server and the port Db2 will listen on for TLS connections. Let’s start with TLS certificates.
Certificates
Now that we have a keystore, we need to create a certificate to represent our server. This will be stored in our keystore and be accessed when
Certificates and the infrastructure surrounding them are designed around a system of trust. A certificate can be trusted because there is someone/something else vouching for it. This someone/something is called a certificate authority (CA). CAs sign certificates indicating they vouch for the authenticity of the certificate. The chain that gets created when CAs vouch for each other and the endpoint certificate is called a certificate chain. When a certificate is signed by a CA, we call them CA-signed certificates.
It is good to mention here that there is also something called a self-signed certificate which are essentially certificates that vouch for themselves. However, in most cases, you will likely want to use a CA-signed certificate. For example, if you have multiple clients connecting to many different databases and instances, a single CA can enable the client to form a TLS session with all databases using the same CA. If a self-signed certificate was used instead, each individual certificate would need to be copied over to each client. However, a self-signed certificate may be appealing if it is in a test environment or if only one or a few instances and a limited number of clients are being used.
Self-Signed certificate
To create a self-signed certificate, run:
gsk8capicmd_64 –cert –create –db /home/db2inst1/server.p12 -label mylabel-dn ‘cn=Test’ -stashed
This will create a certificate with the label “mylabel” in the keystore “/home/db2inst1/server.p12”. The “-dn” option provides the distinct name of our certificate – the only required part of this name is “CN”.
TLS certificates have a public key and a private key. This is important; the server must have both. You can check by listing the certificates in the keystore:
gsk8capicmd_64 –cert –list –db path/to/server.p12 -stashed
This will give output looking like this:
Certificates found
* default, - personal, ! trusted, # secret key
- mylabel
Note the “-” beside our “mylabel”. This indicates that the certificate has both the public and private key in the keystore.
CA-Signed Certificates
Db2 supports using CA-signed as well. To do this, we need to create a Certificate Signing Request:
gsk8capicmd_64 -certreq -create -label mylabel -db /home/db2inst1/server.p12 -stashed -file /path/to/mylabel.csr -dn 'CN=test'
This creates a certificate request associated with the label “mylabel”. Send the resulting /path/to/mylabel.csr to your CA for signing.
After receiving the signed certificate back from your CA, you need to add any root and intermediate certificates to your keystore. This is usually provided by your CA. If these certificates are in separate files, add each one using:
gsk8capicmd_64 -cert -add -db /home/db2inst1/server.p12 -stashed -label root -file /path/to/root/certificate
If the certificates are in a single Base64-encoded file, use:
gsk8capicmd_64 -cert -add -db /home/db2inst1/server.p12 -stashed -file /path/to/certificates
If the file is PKCS12-encoded, use:
gsk8capicmd_64 -cert -import -target /home/db2inset1/server.p12 -target_stashed -db /path/to/certificates.p12 -stashed
Now you can receive (not add!) the certificate into your keystore. Run:
gsk8capicmd_64 -cert -receive -db /home/db2inst1/server.p12 -file /path/to/server.pem -stashed
If you have added your certificate instead of receiving it, the certificate will not be associated with your certificate signing request and you may receive a GSKit 407 error when starting the Db2 server.
At this point, your certificate should be imported into the keystore using the same label provided when you created the CSR. You can confirm using:
$ gsk8capicmd_64 –cert –list –db /home/db2inst1/server.p12 -stashed
Certificates found
* default, - personal, ! trusted, # secret key
! root
- mylabel
(note the “-” beside the server certificate) and:
gsk8capicmd_64 -cert –details –db /home/db2inst1/server.p12 -stashed –label mylabel
TLS Port
Last but not least, let’s talk about the TLS Port.
You can choose any port for Db2 to listen to provided it is not in use. Alternatively, you can use a service name, which is a human-friendly name that maps to a port number. On Linux/Unix systems, service names are defined in /etc/services while on Windows, it is C:\Windows\System32\drivers\etc\services. For our sample setup, we will choose 25100 as our TLS port.
Putting it all together
We have everything we need to enable TLS on the server! We just need to tell Db2 about all our certificates. You can use the following command to update the DBM cfg based on the examples we used above:
db2 update dbm cfg using SSL_SVR_KEYDB /home/db2inst1/server.p12 SSL_SVR_STASH /home/db2inst1/server.sth SSL_SVR_LABEL mylabel SSL_SVCENAME 25100
Only thing left is to actually enable TLS:
db2set DB2COMM=SSL
That’s it! Now (re)start the Db2 server and it is ready to receive TLS connections!
Note: I didn’t mention the other TLS parameters SSL_VERSIONS and SSL_CIPHERSPECS. These two parameters are optional, and Db2 automatically picks the most recently supported TLS version and the strongest supported cipher for the session. There are further intricacies when using these two TLS features, so I will save that for another blog post.
Troubleshooting
You followed all the steps above, but TLS is still not working. What is going on? We’ll try to cover some of the common error scenarios you may have run into and how you can resolve them.
For starters, the primary indicator that something went wrong when TLS is starting up is a SQL5043N when starting up your server:
$ db2start
SQL5043N Support for one or more communications protocols specified in the DB2COMM environment variable failed to start successfully. However, core database manager functionality started successfully.
Uh-oh! Something went wrong! First thing to check is the db2diag.log. Sometimes, the message is straightforward:
2025-09-05-09.57.32.482363-240 E11590E469 LEVEL: Error
PID : 3400479 TID : 140340157736512 PROC : db2sysc
INSTANCE: cyrusng NODE : 000
HOSTNAME: CyrusNg-857tb-x86
EDUID : 1 EDUNAME: db2sysc
FUNCTION: DB2 UDB, common communication, sqlccLoadSSLLibrary, probe:2
MESSAGE : ADM7012E The SSL_SVR_KEYDB DBM configuration parameter was not
configured. Update the SSL_SVR_KEYDB configuration parameter.
In this case, I didn’t set the SSL_SVR_KEYDB DBM cfg parameter. But other errors may not be as obvious, and I will detail them below.
GSKit Error 407
You may encounter the following in the db2diag.log:
2025-09-05-11.19.51.739672-240 I13213E613 LEVEL: Error
PID : 3403116 TID : 140157348996672 PROC : db2sysc
INSTANCE: cyrusng NODE : 000
HOSTNAME: CyrusNg-857tb-x86
EDUID : 1 EDUNAME: db2sysc
FUNCTION: DB2 UDB, common communication, sqlccMapSSLErrorToDB2Error, probe:6552
MESSAGE : DIA3604E The SSL function "sqlccSSLValidateCertificate" failed with
the return code "407" in "sqlccEnvironmentInitCommon".
DATA #1 : String, 27 bytes
GSK_ERROR_BAD_KEYFILE_LABEL
DATA #2 : String, 54 bytes
The specified label in the key file could not be found
Check that the certificate name you provided to SSL_SVR_LABEL is correct. You can do this by running:
db2 get dbm cfg
Correlate this with the certificates in your keystore by doing:
gsk8capicmd_64 –cert –list –db path/to/server.p12 -stashed
This will give output looking like this:
Certificates found
* default, - personal, ! trusted, # secret key
- mylabel
If the certificate label matches what you provided to SSL_SVR_LABEL, then also check that this is a personal certificate (note the “-” beside the certificate). If this isn’t the case, then you will need to recreate or re-import the certificate into the keystore.
Errors with CA-signed certificates
You may encounter errors in the db2diag.log that look something like this:
2025-09-05-12.04.49.796323-240 I11138E2456 LEVEL: Error
PID : 3403630 TID : 140280183383616 PROC : db2sysc
INSTANCE: cyrusng NODE : 000
HOSTNAME: CyrusNg-857tb-x86
EDUID : 1 EDUNAME: db2sysc
FUNCTION: DB2 UDB, common communication, sqlccSSLValidateCertificate, probe:7602 MESSAGE : Certificate Validation Failed
DATA #1 : String, 138 bytes
message, certificate label, TLS 1.3 Status, public key OID, signature algorithm OID, key size,validity start, expiry, validation error log
DATA #2 : String, 118 bytes Validation failure for certificate signedserver: GSKVAL_ERROR_NO_CHAIN_BUILT (575010) - No certificate chain was built
DATA #3 : String, 12 bytes
mylabel
DATA #4 : Boolean, 4 bytes
false
DATA #5 : String, 0 bytes
Object not dumped: Address: 0x00007F95867E5650 Size: 0 Reason: Zero-length data
DATA #6 : String, 0 bytes
Object not dumped: Address: 0x00007F95867E55E0 Size: 0 Reason: Zero-length data
DATA #7 : unsigned integer, 8 bytes
0
DATA #8 : String, 0 bytes
Object not dumped: Address: 0x00007F95867E5730 Size: 0 Reason: Zero-length data
DATA #9 : String, 0 bytes
Object not dumped: Address: 0x00007F95867E56C0 Size: 0 Reason: Zero-length data
DATA #10: String with size, 391 bytes [Class=]GSKVALMethod::X509[Time=]2025:9:5:12:4:49.794[buildChain=][Error=]GSKVAL_ERR_NO_CHAIN_BUILT[Info=]CN=root[Cert=][Issuer=]CN=root[#=]0edd4386f8dc3646[Subject=]CN=test[=Cert][=buildChain]^M
[Class=]GSKVALMethod::PKIX[Time=]2025:9:5:12:4:49.796[buildChain=][Error=]GSKVAL_ERR_NO_CHAIN_BUILT[Info=]CN=root[Cert=][Issuer=]CN=root[#=]0edd4386f8dc3646[Subject=]CN=test[=Cert][=buildChain]^M
CALLSTCK: (Static functions may not be resolved correctly, as they are resolved to the nearest symbol)
...
2025-09-05-12.04.49.804738-240 I13595E583 LEVEL: Error
PID : 3403630 TID : 140280183383616 PROC : db2sysc
INSTANCE: cyrusng NODE : 000
HOSTNAME: CyrusNg-857tb-x86
EDUID : 1 EDUNAME: db2sysc
FUNCTION: DB2 UDB, common communication, sqlccMapSSLErrorToDB2Error, probe:6552 MESSAGE : DIA3604E The SSL function "sqlccSSLValidateCertificate" failed with
the return code "8" in "sqlccEnvironmentInitCommon".
DATA #1 : String, 25 bytes
GSK_ERROR_CERT_VALIDATION
DATA #2 : String, 28 bytes
Certificate validation error
There may be a large variety of reasons for why a certificate failed validation, but one common reason is that you received the certificate correctly into the keystore but forgot to add the root and intermediate certificates. To check if this is the case, run:
gsk8capicmd_64 -cert -validate -db /home/db2inst1/server.p12 -stashed -label mylabel
If there are errors with the certificate chain, you will see something like this:
CTGSK2146W An invalid certificate chain was found.
Additional untranslated info:
GSKKM_LAST_VALIDATION_ERROR: No certificate chain built
GSKKM_VALIDATIONFAIL_SUBJECT: [Class=]GSKVALMethod::PKIX[Issuer=]CN=root[#=]0edd4386f8dc3646[Subject=]CN=test
CTGSK2146W An invalid certificate chain was found.
Make sure you have added all root and intermediate certificates to the keystore. These can be marked with a “!” when you list the certificates:
Certificates found
* default, - personal, ! trusted, # secret key
! root
- mylabel
You may also see similar messages if your certificate does not meet the security requirements of your Db2 server. I hope to detail this in a later blog, but for now, I’ll refer you to our documentation about Db2’s security modes and the page about TLS 1.3 certificate restrictions
If your certificate is using old insecure algorithms, you may see errors similar to the above. You can view the details of your certificate to check if these insecure algorithms are being used by running:
gsk8capicmd_64 –cert –details –db /home/db2inst1/server.p12 -label mylabel
GSKit Error 102 and 408
In the db2diag.log, you may encounter:
2025-09-05-11.01.48.637518-240 I11138E569 LEVEL: Error
PID : 3402527 TID : 139831086671424 PROC : db2sysc
INSTANCE: cyrusng NODE : 000
HOSTNAME: CyrusNg-857tb-x86
EDUID : 1 EDUNAME: db2sysc
FUNCTION: DB2 UDB, common communication, sqlccMapSSLErrorToDB2Error, probe:530
MESSAGE : DIA3604E The SSL function "gsk_environment_init" failed with the
return code "102" in "sqlccEnvironmentInitCommon".
DATA #1 : String, 20 bytes
GSK_KEYFILE_IO_ERROR
DATA #2 : String, 25 bytes
I/O error reading keyfile
or
2025-09-05-10.24.38.250741-240 I57687E665 LEVEL: Error
PID : 3402070 TID : 139753546573376 PROC : db2sysc
INSTANCE: cyrusng NODE : 000
HOSTNAME: CyrusNg-857tb-x86
EDUID : 1 EDUNAME: db2sysc
FUNCTION: DB2 UDB, common communication, sqlccMapSSLErrorToDB2Error, probe:530
MESSAGE : DIA3604E The SSL function "gsk_environment_init" failed with the
return code "408" in "sqlccEnvironmentInitCommon".
DATA #1 : String, 30 bytes
GSK_ERROR_BAD_KEYFILE_PASSWORD
DATA #2 : String, 110 bytes
The specified key file password is incorrect. The key file could not be used. The key file may also be corrupt
The first thing to check is that you’ve specified the correct keystore and stash file pairing for SSL_SVR_STASH and SSL_SVR_KEYDB. You can check this by using:
db2 get dbm cfg
If you are sure that the DBM cfg is set correctly but are still getting these errors, check that the server can access the keystore and stash file. On Linux/Unix, these should be accessible by the instance owner. The permissions should be:
$ ls -l server.p12 server.sth
-rw------- 1 db2inst1 db2inst1 25599 Aug 14 10:52 server.p12
-rw------- 1 db2inst1 db2inst1 193 Oct 24 2024 server.sth
On Windows, these files should be accessible by the Db2 service account. You can find the account your Db2 service is running under by hitting Win+r and running services.msc. Search for the Db2 service and the account will be mentioned under the “Log On As” column.
Then, make sure your keystore is accessible by this account:
Remember to make sure the entire path is accessible to the instance owner/service account! If you have determined that the instance owner or Db2 service account can access the files, then double check the version of GSKit installed on your system. You can do this using:
gsk8ver_64
It should print out the version of each GSKit library in the GSKit installation:
...
libgsk8km2_64.so
============
@(#)CompanyName: IBM Corporation
@(#)LegalTrademarks: IBM
@(#)FileDescription: IBM Global Security Toolkit
@(#)FileVersion: 8.0.60.1
@(#)InternalName: gskkm2
@(#)LegalCopyright: Licensed Materials - Property of IBM GSKit
(C) Copyright IBM Corp.1995, 2024
All Rights Reserved. US Government Users
Restricted Rights - Use, duplication or disclosure
restricted by GSA ADP Schedule Contract with IBM Corp.
@(#)OriginalFilename: libgsk8km2_64.so
@(#)ProductName: gsk8l (GoldCoast Build 8.0.55) 240525_8.0.60.1
@(#)ProductVersion: 8.0.60.1
...
Be careful! gsk8ver_64 will rely on LD_LIBRARY_PATH (Linux), LIBPATH (AIX), and PATH (Windows) to find the GSKit libraries, so if there are multiple GSKit installations on your system, make sure those variables point GSKit to the one used by the server. On Linux/Unix systems, use the export command. On Windows, you can use set or modify the system PATH.
The GSKit version should match those found here for official Db2 releases and here for security special builds. If they don’t, then install the correct version of GSKit. If the GSKit version is older than 8.0.50.69, then you will need to recreate the keystore and stash file with a newer GSKit.
You can also check that you can access the keystore using the stash file:
gsk8capicmd_64 –cert –list –db /home/db2inst1/server.p12 -stashed
If the command outputs a list of certificates, then we know the stash file is not corrupted. Otherwise, you will need to recreate the keystore and stash files by following the steps outlined in Keystore and Stash Files.
Invalid TLS port
If your chosen TLS port is in use by another process, you may see the following message in the db2diag.log:
2025-09-05-11.10.29.502354-240 E62274E766 LEVEL: Error
PID : 3402800 TID : 139709405718080 PROC : db2sysc
INSTANCE: cyrusng NODE : 000
HOSTNAME: CyrusNg-857tb-x86
EDUID : 1 EDUNAME: db2sysc
FUNCTION: DB2 UDB, common communication, sqlcctcpconnmgr, probe:46
MESSAGE : ADM7007E The SVCENAME DBM configuration parameter, "9083", is
configured with a port or a service name. When it is configured with
a service name, the TCP/IP services files is used to map the service
name to a port number. The port specified in this field is being
used by another process. Resolve this problem by either deleting the
process using the port or use another port.
This means another process is listening on the chosen TLS port. You will need to choose another port or terminate the process listening on that port. You can find out what ports are being used with:
netstat –tulnp
Some ports are restricted and are reserved for certain purposes by the OS. In these cases, you may see something like:
2025-09-05-11.08.14.492921-240 I13762E385 LEVEL: Error
PID : 3402674 TID : 140084338746944 PROC : db2sysc
INSTANCE: cyrusng NODE : 000
HOSTNAME: CyrusNg-857tb-x86
EDUID : 1 EDUNAME: db2sysc
FUNCTION: DB2 UDB, common communication, sqlcctcpconnmgr, probe:47
MESSAGE : DIA3202C The TCP/IP call "bind" returned an errno="13".
Conclusion
I hope this has been an informative read on how to set up the Db2 server to use TLS. Your server is now ready to communicate with clients in a secure manner. Now that we have our server set up, we will talk about setting up the client in the next blog. Until next time!
Further Reading
About the Authors
Cyrus Ng is a Software Developer on the Db2 Security team at the IBM Toronto Lab with a Bachelor's in Computing from Queen’s University. He has worked with various security features in Db2, such as TLS 1.3 support, hostname validation, and audit.
Greg Stager is the security architect for Db2 LUW at the IBM Toronto Lab. Greg has been a member of the Db2 security development team since 2000, where he has worked on all aspects of security within Db2, including authentication, authorization, auditing, and encryption. Greg is a primary contributor to the Db2 LUW CIS Benchmark, and a Certified Information System Security Professional (CISSP).
Nataliya Prokoshyna is a software development manager for Db2 LUW at the IBM Canada Lab. As a senior member of the Db2 security development team, Nataliya has worked on authentication, authorization, auditing and encryption, PSIRT, and other aspects of security within Db2.