I Tested TLS Connections Using PQ Key Exchange, Now Supported in Aurora MySQL 8.4.8
This page has been translated by machine translation. View original
Introduction
I introduced Aurora MySQL 8.4.8, announced on September 3, 2026, in a previous article.
In this article, I cover the PQC support that I said I would introduce later in the previous article.
8.4.8 supports X25519MLKEM768 and SecP256r1MLKEM768 as PQC hybrid key exchange in TLS 1.3.
This time, I connected from a JDK 27 client and checked the key exchange group selected in the TLS handshake.
Verification Details
I placed one EC2 instance (Amazon Linux 2023, ARM64) in the same VPC as Aurora, and connected from a JDK 27 container running on it.
Verification Environment
For the verification, I used the pre-GA JDK 27 (build 27+35), Aurora MySQL 8.4.8, and MySQL Connector/J 9.0.0. The JDK version is as follows.
openjdk version "27" 2026-09-15
OpenJDK Runtime Environment (build 27+35-2325)
OpenJDK 64-Bit Server VM (build 27+35-2325, mixed mode, sharing)
I checked the version and TLS settings of the Aurora instance I connected to with the following queries.
SELECT VERSION();
SHOW VARIABLES LIKE 'tls%';
SHOW VARIABLES LIKE 'ssl%';
- VERSION(): 8.4.8
- tls_version: TLSv1.2,TLSv1.3
- tls_ciphersuites: TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384
I found no item in the tls% and ssl% variables for enabling or disabling PQ key exchange.
Connection Client
The source of the JDK and the version of Connector/J are as shown in the Dockerfile.
Dockerfile for the JDK 27 client
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
curl ca-certificates \
&& rm -rf /var/lib/apt/lists/*
ARG JDK_URL=https://download.java.net/java/GA/jdk27/55ce5470a6294008af0057ff4626d0e5/35/GPL/openjdk-27_linux-aarch64_bin.tar.gz
RUN curl -fsSL ${JDK_URL} | tar -xz -C /opt \
&& ln -s /opt/jdk-27 /opt/java
ENV JAVA_HOME=/opt/java
ENV PATH="${JAVA_HOME}/bin:${PATH}"
WORKDIR /app
ADD https://repo1.maven.org/maven2/com/mysql/mysql-connector-j/9.0.0/mysql-connector-j-9.0.0.jar /app/mysql-connector-j.jar
COPY MysqlTlsTest.java .
RUN javac -cp mysql-connector-j.jar MysqlTlsTest.java
CMD ["java", "-Djavax.net.debug=ssl:handshake", "-cp", ".:mysql-connector-j.jar", "MysqlTlsTest"]
The configuration part of the code used for the connection is as follows. The handshake log obtained with this configuration is from a connection with certificate verification disabled.
String url = String.format("jdbc:mysql://%s:%s/%s", host, port, database);
Properties props = new Properties();
props.setProperty("user", user);
props.setProperty("password", password);
props.setProperty("useSSL", "true");
props.setProperty("requireSSL", "true");
props.setProperty("verifyServerCertificate", "false");
The three SSL-related properties above are deprecated in Connector/J 8 and later. How to write the configuration when enabling certificate verification is described later.
I ran the build and execution with the following commands.
docker build -f Dockerfile.jdk27 -t mysql-tls-java-jdk27 java-client/
docker run --rm \
-e MYSQL_HOST="$MYSQL_HOST" \
-e MYSQL_PORT=3306 \
-e MYSQL_USER=admin \
-e MYSQL_PASSWORD="$MYSQL_PASSWORD" \
-e MYSQL_DATABASE=mysql \
mysql-tls-java-jdk27 > jdk27-handshake.log 2>&1
The key exchange group appears only in the handshake log. I ran it with -Djavax.net.debug=ssl:handshake added in the Dockerfile's CMD, and read the ServerHello in the output log.
Quick Check with OpenSSL
If you cannot prepare a PQC-capable JDK right away, you can first check whether the OpenSSL on the client side has X25519MLKEM768. I ran the following commands on this EC2 instance.
openssl version
openssl list -tls-groups
The OpenSSL version and supported groups were as follows.
OpenSSL 3.5.7 9 Jun 2026 (Library: OpenSSL 3.5.7 9 Jun 2026)
secp256r1:secp384r1:secp521r1:x25519:x448:brainpoolP256r1tls13:brainpoolP384r1tls13:brainpoolP512r1tls13:ffdhe2048:ffdhe3072:ffdhe4096:ffdhe6144:ffdhe8192:MLKEM512:MLKEM768:MLKEM1024:SecP256r1MLKEM768:X25519MLKEM768:SecP384r1MLKEM1024
MLKEM-family groups were listed in the latter half of the list, and X25519MLKEM768 was included. When PQ key exchange is not established, this can be used as a way to first isolate the client-side support status. However, a group being present in the library is a separate matter from it being offered and selected during a connection. Whether it was established is read from the following handshake log.
Checking the Handshake
The JDK 27 client offered X25519MLKEM768 in the supported_groups of the ClientHello.
"supported_groups (10)": {
"named groups": [X25519MLKEM768, x25519, secp256r1, secp384r1, secp521r1, x448, ffdhe2048, ffdhe3072, ffdhe4096]
},
In the following ServerHello, Aurora selected X25519MLKEM768.
"ServerHello": {
"server version" : "TLSv1.2",
"cipher suite" : "TLS_AES_256_GCM_SHA384(0x1302)",
"compression methods" : "00",
"extensions" : [
"key_share (51)": {
"server_share": {
"named group": X25519MLKEM768
The key_share in TLS 1.3 is the agreed key exchange group itself. From this "named group": X25519MLKEM768, we can confirm that this group was used by both the server and the client. The server version in the quoted portion is a field in which TLSv1.2 is placed for compatibility. The actually negotiated version appears in Negotiated protocol version in the log.
javax.net.ssl|DEBUG|30|main|2026-09-07 04:41:02.984 UTC|ServerHello.java:1049|Negotiated protocol version: TLSv1.3
Not only the handshake but also the connection was established, and the session's cipher suite and TLS version were the following values.
Connected successfully!
=== TLS Session Status ===
Ssl_cipher: TLS_AES_256_GCM_SHA384
Ssl_version: TLSv1.3
Combined Use with Certificate Verification
I checked whether the same group is selected even when certificate verification is enabled.
I set Connector/J's sslMode to VERIFY_IDENTITY, imported the RDS CA bundle into the truststore, and ran it. The bundle used was https://truststore.pki.rds.amazonaws.com/ap-northeast-1/ap-northeast-1-bundle.pem (retrieved on 2026-09-07). The connection properties are as follows.
Properties props = new Properties();
props.setProperty("user", user);
props.setProperty("password", password);
props.setProperty("sslMode", "VERIFY_IDENTITY");
props.setProperty("trustCertificateKeyStoreUrl", "file:/app/rds-truststore.p12");
props.setProperty("trustCertificateKeyStoreType", "PKCS12");
props.setProperty("trustCertificateKeyStorePassword", "changeit");
With this configuration as well, the server_share in the ServerHello was the same X25519MLKEM768.
Summary
With Aurora MySQL 8.4.8, which supports key exchange via PQC, PQ key exchange was established by making the client PQC-capable. The establishment was confirmed in the ServerHello of the handshake log.
Government agencies and others have indicated a policy of aiming to complete the PQC migration by 2035.
PQ key exchange became available in Aurora MySQL 8.4.8, following MySQL 26.7.0 in July 2026. On the client side as well, JDK 27, in which PQ key exchange is enabled by default, is scheduled to reach GA on 2026-09-15.
If you may adopt Aurora MySQL in the future and may be required to support PQC, I recommend checking whether PQ key exchange can be used with a combination of Aurora MySQL 8.4.8 and PQC-capable middleware and JDK.
Reference Links
