SSL in MySQL Connector/J encrypts all data (other than the initial handshake) between the JDBC driver and the server. The performance penalty for enabling SSL is an increase in query processing time between 35% and 50%, depending on the size of the query, and the amount of data it returns.
For SSL support to work, you must have the following:
A JDK that includes JSSE (Java Secure Sockets Extension), like JDK-1.4.1 or newer. SSL does not currently work with a JDK that you can add JSSE to, like JDK-1.2.x or JDK-1.3.x due to the following JSSE bug: http://developer.java.sun.com/developer/bugParade/bugs/4273544.html
A MySQL server that supports SSL and has been compiled and configured to do so, which is MySQL 4.0.4 or later. For more information, see Section 6.3.9.2, “Configuring MySQL for SSL”.
A client certificate (covered later in this section)
The system works through two Java truststore files, one file
contains the certificate information for the server
(truststore in the examples below). The
other file contains the certificate for the client
(keystore in the examples below). All Java
truststore files are password protected by supplying a suitable
password to the keytool when you create the
files. You need the file names and associated passwords to
create an SSL connection.
You will first need to import the MySQL server CA Certificate
into a Java truststore. A sample MySQL server CA Certificate is
located in the SSL subdirectory of the
MySQL source distribution. This is what SSL will use to
determine if you are communicating with a secure MySQL server.
Alternatively, use the CA Certificate that you have generated or
been provided with by your SSL provider.
To use Java's keytool to create a truststore
in the current directory , and import the server's CA
certificate (cacert.pem), you can do the
following (assuming that keytool is in your
path. The keytool is typically located in the
bin subdirectory of your JDK or JRE):
shell> keytool -import -alias mysqlServerCACert \ -file cacert.pem -keystore truststore
Enter the password when prompted for the keystore file. Interaction with keytool looks like this:
Enter keystore password: *********
Owner: EMAILADDRESS=walrus@example.com, CN=Walrus,
O=MySQL AB, L=Orenburg, ST=Some-State, C=RU
Issuer: EMAILADDRESS=walrus@example.com, CN=Walrus,
O=MySQL AB, L=Orenburg, ST=Some-State, C=RU
Serial number: 0
Valid from:
Fri Aug 02 16:55:53 CDT 2002 until: Sat Aug 02 16:55:53 CDT 2003
Certificate fingerprints:
MD5: 61:91:A0:F2:03:07:61:7A:81:38:66:DA:19:C4:8D:AB
SHA1: 25:77:41:05:D5:AD:99:8C:14:8C:CA:68:9C:2F:B8:89:C3:34:4D:6C
Trust this certificate? [no]: yes
Certificate was added to keystoreYou then have two options: either import the client certificate that matches the CA certificate you just imported, or create a new client certificate.
Importing an existing certificate requires the certificate to be in DER format. You can use openssl to convert an existing certificate into the new format. For example:
shell> openssl x509 -outform DER -in client-cert.pem -out client.cert
Now import the converted certificate into your keystore using keytool:
shell> keytool -import -file client.cert -keystore keystore -alias mysqlClientCertificate
To generate your own client certificate, use
keytool to create a suitable certificate and
add it to the keystore file:
shell> keytool -genkey -keyalg rsa \
-alias mysqlClientCertificate -keystore keystore
Keytool will prompt you for the following information, and
create a keystore named keystore in the
current directory.
Respond with information that is appropriate for your situation:
Enter keystore password: *********
What is your first and last name?
[Unknown]: Matthews
What is the name of your organizational unit?
[Unknown]: Software Development
What is the name of your organization?
[Unknown]: MySQL AB
What is the name of your City or Locality?
[Unknown]: Flossmoor
What is the name of your State or Province?
[Unknown]: IL
What is the two-letter country code for this unit?
[Unknown]: US
Is <CN=Matthews, OU=Software Development, O=MySQL AB,
L=Flossmoor, ST=IL, C=US> correct?
[no]: y
Enter key password for <mysqlClientCertificate>
(RETURN if same as keystore password):
Finally, to get JSSE to use the keystore and truststore that you
have generated, you need to set the following system properties
when you start your JVM, replacing
path_to_keystore_file with the full
path to the keystore file you created,
path_to_truststore_file with the path
to the truststore file you created, and using the appropriate
password values for each property. You can do this either on the
command line:
-Djavax.net.ssl.keyStore=path_to_keystore_file-Djavax.net.ssl.keyStorePassword=password-Djavax.net.ssl.trustStore=path_to_truststore_file-Djavax.net.ssl.trustStorePassword=password
Or you can set the values directly within the application:
System.setProperty("javax.net.ssl.keyStore","path_to_keystore_file");
System.setProperty("javax.net.ssl.keyStorePassword","password");
System.setProperty("javax.net.ssl.trustStore","path_to_truststore_file");
System.setProperty("javax.net.ssl.trustStorePassword","password");
You will also need to set useSSL to
true in your connection parameters for MySQL
Connector/J, either by adding useSSL=true to
your URL, or by setting the property useSSL
to true in the
java.util.Properties instance you pass to
DriverManager.getConnection().
You can test that SSL is working by turning on JSSE debugging (as detailed below), and look for the following key events:
...
*** ClientHello, v3.1
RandomCookie: GMT: 1018531834 bytes = { 199, 148, 180, 215, 74, 12, »
54, 244, 0, 168, 55, 103, 215, 64, 16, 138, 225, 190, 132, 153, 2, »
217, 219, 239, 202, 19, 121, 78 }
Session ID: {}
Cipher Suites: { 0, 5, 0, 4, 0, 9, 0, 10, 0, 18, 0, 19, 0, 3, 0, 17 }
Compression Methods: { 0 }
***
[write] MD5 and SHA1 hashes: len = 59
0000: 01 00 00 37 03 01 3D B6 90 FA C7 94 B4 D7 4A 0C ...7..=.......J.
0010: 36 F4 00 A8 37 67 D7 40 10 8A E1 BE 84 99 02 D9 6...7g.@........
0020: DB EF CA 13 79 4E 00 00 10 00 05 00 04 00 09 00 ....yN..........
0030: 0A 00 12 00 13 00 03 00 11 01 00 ...........
main, WRITE: SSL v3.1 Handshake, length = 59
main, READ: SSL v3.1 Handshake, length = 74
*** ServerHello, v3.1
RandomCookie: GMT: 1018577560 bytes = { 116, 50, 4, 103, 25, 100, 58, »
202, 79, 185, 178, 100, 215, 66, 254, 21, 83, 187, 190, 42, 170, 3, »
132, 110, 82, 148, 160, 92 }
Session ID: {163, 227, 84, 53, 81, 127, 252, 254, 178, 179, 68, 63, »
182, 158, 30, 11, 150, 79, 170, 76, 255, 92, 15, 226, 24, 17, 177, »
219, 158, 177, 187, 143}
Cipher Suite: { 0, 5 }
Compression Method: 0
***
%% Created: [Session-1, SSL_RSA_WITH_RC4_128_SHA]
** SSL_RSA_WITH_RC4_128_SHA
[read] MD5 and SHA1 hashes: len = 74
0000: 02 00 00 46 03 01 3D B6 43 98 74 32 04 67 19 64 ...F..=.C.t2.g.d
0010: 3A CA 4F B9 B2 64 D7 42 FE 15 53 BB BE 2A AA 03 :.O..d.B..S..*..
0020: 84 6E 52 94 A0 5C 20 A3 E3 54 35 51 7F FC FE B2 .nR..\ ..T5Q....
0030: B3 44 3F B6 9E 1E 0B 96 4F AA 4C FF 5C 0F E2 18 .D?.....O.L.\...
0040: 11 B1 DB 9E B1 BB 8F 00 05 00 ..........
main, READ: SSL v3.1 Handshake, length = 1712
...
JSSE provides debugging (to stdout) when you
set the following system property:
-Djavax.net.debug=all This will tell you what
keystores and truststores are being used, as well as what is
going on during the SSL handshake and certificate exchange. It
will be helpful when trying to determine what is not working
when trying to get an SSL connection to happen.

User Comments
Yet again, the MySQL documentation fails abysmally. Followed the steps above to the letter - didn't work. AAAARG!
Where exactly did things fall apart for you? I've used the steps here recently and they worked for me. Without telling the documentation folks where _exactly_ things went wonky, they're not going to be able to fix things to help you out.
I've found that connecting from a Java client using a self-signed certificate does not work for me. The client certificate needs to be signed by the CA that the MySQL server trusts.
I've read some of the discussions on the MySQL forums about this and understand that others are/were having the same problem as me. After some experimentation, I've got it to work and wanted to share that information here.
The http://access1.sun.com/techarticles/Keytool.html site was an absolute essential source of information in getting over the "Failed to establish chain from reply” error message that I kept on getting when trying to import a certificate signed by a CA that is not trusted by java.
For testing purposes, I have setup a local CA using openssl. Also, I am on a Linux environment and using MySQL version 5.0.37. I am assuming that the local CA has already been setup and will focus on the steps I followed to ensure that Java keystore can import the signed certificate.
1. Create a self-signed certificate and key pair so that Java can use it
$ keytool -genkeypair -keyalg rsa -validity 3650 -alias mysqlClientCertificate -keystore keystore
2 Export that self-signed certificate
This is so that our CA can sign it and send it back as a signed response.
$ keytool -certreq -v -alias mysqlclientcertificate -keystore keystore -file javaclient.cr
3 CA signs the certificate request
$ openssl ca -out javaclientPEM.csr -config ./openssl.cnf -infiles javaclient.cr
(the openssl.cnf file has the typical configuration values and nothing special)
4 Combine two certificates
Combine the just signed certificate with the CA’s root certificate. This is so that that key tool utility can successfully verify the signed certificate. The way it verifies this is by first checking to see if it trusts the issuer. This is done by going to the $JAVA_HOME/ jre/lib/security/cacerts store to check of the issuer is trusted.
Unfortunately, because we are acting as our own certificate authority, we won’t be in that cacerts file.
The article mentioned at the beginning of this section recommends two ways of helping keytool to do its work. The first approach is to import our CA’s certificate into the $JAVA_HOME/ jre/lib/security/cacerts store. A second way is to put the CA’s certificate first followed by the just signed certificate. I used the second way.
In the below command, please note that the importance of cacert file coming before the just signed cert is critical. Without this sequence, importing into the java keystore would fail with the exception "Failed to establish chain from reply”
$ openssl crl2pkcs7 -nocrl -certfile cacert.pem -certfile javaclientPEM.csr -outform DER -out combined_responsepk7.der
5 Import into the key store
Import the “rootCA+signed request” file into the key store. Note that this combined file needs to be in pk7 and DER format
$ keytool -importcert -v -alias mysqlclientcertificate -file combined_responsepk7.der -keystore keystore
6 List out the key store
List the contents of the key store to verify that the previously self-signed certificate associated with the mysqlclientcertificate alias is now issued by our CA.
$ keytool -list -v -keystore keystore
7.Use a simple java program to test the connection. Of course, to test it, you need to have mysql-connector-java-5.0.5-bin.jar in the CLASSPATH (this is the version of the connector I used)
import java.sql.*;
public class HelloWorld{
public static void main(String args[]){
System.out.println("Starting program");
try {
//Register the JDBC driver for MySQL.
Class.forName("com.mysql.jdbc.Driver");
String url =
"jdbc:mysql://localhost:3306/mysql?useSSL=true&requireSSL=true";
Connection con =
DriverManager.getConnection(
url,"javatestuser", "secretpassword");
//Display URL and connection information
System.out.println("URL: " + url);
System.out.println("Connection: " + con);
con.close();
} catch(Exception ex){
ex.printStackTrace();
}
}
}
8. compile and run the program
$ javac HelloWorld.java
$ java \
-Djavax.net.ssl.keyStore=/home/ca/java/keystore \
-Djavax.net.ssl.keyStorePassword=passpass \
-Djavax.net.ssl.trustStore=/home/ca/java/truststore \
-Djavax.net.ssl.trustStorePassword=passpass \
-Djavax.net.debug=all \
HelloWorld
the -D debug all is helpful to see what's happening as suggested in the documentation.
Note that the trust store contains our local CA's root cert.
Note that javatestuser inside of my mysql database instance has been setup with the GRANT command to require SSL..etc.
I was able to establish a ssl connection using these instructions, but I had to make a couple adjustments which were to exclude the steps for creating a client entry in the keystore as well as excluding System.setProperty(...) for both the entries involving %keyStore%.
By following the instructions exactly, I was able to instantiate the mysql server with ssl capabilities. However, I repeatedly received Communications link failure when attempting to connect to the database until making the exclusions described above.
(Nearly the) same for me as with the above comment - when trying to add the client cert, I was getting "erreur keytool : java.security.SignatureException: Signature does not match.".
I have a self-signed certs setup.
In short, by doing 'keytool -import -alias ca-key.pem -file ca-cert.pem -keystore truststore' on the client machine (OS X.5.6)
and
GRANTing necessary priviledges on the to be accessed by Java database on the server machine to the appropriated user@the client machine's network address (see http://forums.mysql.com/read.php?30,165914,165941)
I was able to use the remote db through an SSL connection with Netbeans 6.5 by passing it the following JDBC URL:
jdbc:mysql://server.tld/db_name?verifyServerCertificate=false&useSSL=true&requireSSL=true
Slightly shorter than the original tutorial(s) isn't it? ;)
The problem with this documentation and with many of the comments is that they don't specify what KIND of SSL connection they are trying to set up. They all say something like "GRANT user with appropriate syntax to require use of SSL". But that begs the question which kind of SSL access they are trying to create. This is important to know.
In Stiepan Aurélien's comment above (not to pick on him, many comments have this problem) for example, it seems that he is doing "REQUIRE SSL" - that is, simple encryption of the data transmission rather than "REQUIRE X509" which encompasses both encryption and authentication. That is why his method can be simpler.
But users need to understand which of these things they are trying to do, and there should be separate sets of instructions appropriate to each choice. Instead we have something of a jumble here.
NOTE:
1) If you are taking an X.509 cert and key from another source (such as openssl output) and trying to use it as the client side certificate.
You can import this into JSSE by exporting from openssl as PKCS12 format:
openssl -export -in mynew.crt -inkey mynew.key -out mynew.p12 -name "mynew"
Password: password1234
You can import into JSSE then using:
keytool -importkeystore -destkeystore keystore -deststorepass keyPassword -srckeystore mynew.p12 -srcstorepass password1234 -srcstoretype PKCS12 -alias mynew
2) You MUST ensure the "keystore password" and the private "key password" are idential (since it is possible for them to end up different). Since the way ExportControlled#getSSLSocketFactoryDefaultOrConfigured(MysqlIO) works it is uses the same password as configured from "clientCertificateKeyStorePassword" to both open the key store file *the JKS format file) and to decrypt the private key inside the file.
If you are having a problem that you get UnrecoverableKeyException "can not recover key" then you can change the password of the key with:
keytool -keypasswd -keystore keystore -alias mynew
Enter keystore password: keyPassword
Enter key password for <mynew>: password1234
New key password for <mynew>: keyPassword
Re-enter new key password for <mynew>: keyPassword
Note this example of the mismatch between "keystore password" and "key password" is kind of based on having followed option item 1 above.
After LITERALLY SPENDING A WEEK DOING THIS I have finally managed to connect using a client certifiacte (REQUIRES X509 on the user defintion)!!!!
rem NOTE: these commands are run using the Java 6 (1.6) JDK as it requires the "-importkeystore" command
rem which is not available before this JDK version.
rem Import the self signed Certifacte Authority certificate into a keystore.
keytool -import -alias mysqlCACert -file ca-cert.pem -keystore truststore -storepass truststore
rem Shows only the signed certificate.
keytool -v -list -keystore truststore -storepass truststore
rem Create a PKCS12 file from an existing signed client certifcate and its private key.
rem set password to "keystore".
openssl pkcs12 -export -in client-cert.pem -inkey client-key.pem -out client.p12 -name clientalias -CAfile ca-cert.pem -caname root
rem Import the combined certificate and private key into the keystore.
keytool -importkeystore -deststorepass keystore -destkeystore keystore -srckeystore client.p12 -srcstoretype PKCS12 -srcstorepass keystore -alias clientalias
Then specify the trusted certifcates file (the truststore) and the client certificate/key file (the keystore) in your Java application either via the connection URL, via the JVM start-up parameter arguments (-D<var>=<val>,...), or System.setProperty(var,val),...
It actually works!!!
assuming you are debugging ssl using -Djavax.net.debug=all or System.setProperty("javax.net.debug","all");
If you faced an Eexception of type (Communications link failure:
The last packet successfully received from the server was 546 milliseconds ago.
The last packet sent successfully to the server was 531 milliseconds ago.)
it is likely to find this line logged by javax.net.debug=all
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA
This TLS_DHE_RSA_WITH_AES_256_CBC_SHA is the standard DHE-RSA-AES256-SHA cipher used by Mysql Server 5.6
on mysql client type
mysql> \s
you will find
Cipher in use is DHE-RSA-AES256-SHA
Then solution for this exception, you MUST update JDK 7 JSSE by updating JCE from JDK download page (Java SE Downloads) find and download (Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 7) then replace local_policy.jar & US_export_policy.jar as in README file section installation
paste them to JDK_HOME/jre/lib/security
and also, for windows users past them to JRE on program files
JRE_HOME/lib/security
I've updated JCE even I'm using jdk1.7.0 update 17 at this post time
Now this line must disappear from javax.net.debug=all logging
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA
************************************************
** Connect JDBC SSL using X509 user
************************************************
** Ref. http://bugs.mysql.com/bug.php?id=68957
************************************************
If you have followed steps to create CA, Server, Client certificates and you can connect using mysql with no errors logged to mysql.err; the file used with variable log_erro=/file/name on my.cnf
> http://dev.mysql.com/doc/refman/5.6/en/creating-ssl-certs.html
> Example 2: Creating SSL Files Using a Script on Unix
You can continue to connect Connector/J to MySQL using user created REQUIRE X509
*****************************
** 1st- Create X509 user
*****************************
a- Check that certificate signed correctly with Certificate Authority
openssl verify -CAfile ca-cert.pem client-cert.pem
a message like "/client-cert.pem: OK" shall out
b- obtain certificate Issuer and Subject using
openssl x509 -noout -in client-cert.pem -issuer
openssl x509 -noout -in client-cert.pem -subject
c- Use out put of step (b) to fill GRANT statement ISSUER & SUBJECT parameters with obtained output
CREATE USER 'user_name'@'localhost' IDENTIFIED BY 'pass_word';
GRANT ALL PRIVILEGES ON database.* TO 'user_name'@'localhost' IDENTIFIED BY 'pass_word' REQUIRE X509;
GRANT ALL PRIVILEGES ON *.* TO 'user_name'@'localhost' IDENTIFIED BY 'pass_word' REQUIRE
ISSUER '/C=FI/ST=Country/L=City/O=Organization/OU=Organization Unit/CN=CERTIFICATE AUTHORITY/emailAddress=email@domain.com'
AND SUBJECT '/C=FI/ST=Country/L=City/O=Organization/OU=Organization Unit/CN=CLIENT CERTIFICATE NAME/emailAddress=email@domain.com'
AND CIPHER 'DHE-RSA-AES256-SHA';
FLUSH PRIVILEGES;
d- validate user created, by successfully login using
> mysql -u user_name -p \
--ssl-ca=/opt/mysq/cert/ca-cert.pem \
--ssl-cert=/opt/mysq/cert/client-cert.pem \
--ssl-key=/opt/mysq/cert/client-key.pem
* or run command
> mysql -u user_name -p
after configure client section at configuration file my.cnf then connect using mysql client command line; no need to restart MySQL server after this update since it is client side only
[client]
ssl=ON
ssl-ca=/opt/mysq/cert/ca-cert.pem
ssl-cert=/opt/mysql/cert/client-cert.pem
ssl-key=/opt/mysql/cert/client-key.pem
*****************************
** 2nd- JDBC configuration
*****************************
following steps by Alexander Soklakov from
http://dev.mysql.com/doc/refman/5.6/en/connector-j-reference-using-ssl.html
http://softteco.blogspot.ru/2010/05/create-java-keystore-file-from-existing.html
1st- for SSL user user use the certificate conversions and TrustStore and KeyStore sample documented here
2nd- for X509 user user use the following steps:
a- add Certificate Authority to a new TrustStore
keytool -import -alias mysqlCACert -file ca-cert.pem -keystore truststore -storepass pass_word -deststoretype JKS
b- Converting openssl created client certificate to accepted java keystore PKCS12
openssl pkcs12 -export -in client-cert.pem -inkey client-key.pem -certfile client-cert.pem -name "Name" -out client.p12
a- Add new PKCS12 certificate to key store JKS type
keytool -importkeystore -srckeystore client.p12 -srcstoretype pkcs12 -destkeystore keystore -storepass pass_word -deststoretype JKS
2nd- configure TrustStore and KeyStore as in documentation
either:
-Djavax.net.ssl.keyStore=path_to_keystore_file
-Djavax.net.ssl.keyStorePassword=password
-Djavax.net.ssl.trustStore=path_to_truststore_file
-Djavax.net.ssl.trustStorePassword=password
OR:
System.setProperty("javax.net.ssl.keyStore","path_to_keystore_file");
System.setProperty("javax.net.ssl.keyStorePassword","pass_word");
System.setProperty("javax.net.ssl.trustStore","path_to_truststore_file");
System.setProperty("javax.net.ssl.trustStorePassword","pass_word");
OR:
try {
mysqlDS = new MysqlDataSource();
mysqlDS.setUseSSL(true);
mysqlDS.setRequireSSL(true);
mysqlDS.setVerifyServerCertificate(true);
mysqlDS.setLogger("com.mysql.jdbc.log.StandardLogger");
mysqlDS.setTrustCertificateKeyStoreType("JKS");
mysqlDS.setTrustCertificateKeyStoreUrl("file:/truststore/url");
mysqlDS.setTrustCertificateKeyStorePassword("pass_word");
mysqlDS.setClientCertificateKeyStoreType("JKS");
mysqlDS.setClientCertificateKeyStoreUrl("file:/keystore/url");
mysqlDS.setClientCertificateKeyStorePassword("pass_word");
mysqlDS.setServerName("localhost");
mysqlDS.setPort(3066);
mysqlDS.setDatabaseName("database_name");
// Create a connection object
connection = mysqlDS.getConnection("user_name", "pass_word");
} catch (Exception x) {
}
3rd- Check JSSE output log tracked by -Djavax.net.debug=all that this line is not exist or you will get Communications link failure
------------
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA
------------
To solve problem see previous comment
4th- Check Connector J output tracked by mysqlDS.setLogger("com.mysql.jdbc.log.StandardLogger");
-----------
URL jdbc:mysql://127.0.0.1:50050/database_name
Driver Version mysql-connector-java-5.1.23 ( Revision: ${bzr.revision-id} )
Connected...
--------------
- Now every thing shall work fine as expected
- to rest assured every thing is working properly rerun this SQL statement and corrupt issuer or subject content
GRANT ALL PRIVILEGES ON *.* TO 'user_name'@'localhost' IDENTIFIED BY 'pass_word' REQUIRE
ISSUER '/C=FI/ST=Country/L=City/O=Organization/OU=Organization Unit/CN=CA CORRUPT DATA HERE/emailAddress=email@domain.com'
AND SUBJECT '/C=FI/ST=Country/L=City/O=Organization/OU=Organization Unit/CN=Client CORRUPT DATA HERE/emailAddress=email@domain.com'
AND CIPHER 'DHE-RSA-AES256-SHA';
try to connect using JDBC or mysql client tool command line
mysql.err shall show something like :
2013-04-17 11:25:51 764 [Note] X509 issuer mismatch: should be '/C=FI/ST=Country/L=City/O=Organization/OU=Organization Unit/CN=Certificate Authority Name/emailAddress=email@domain.com'
2013-04-17 11:25:51 764 [Note] X509 subject mismatch: should be '/C=FI/ST=Country/L=City/O=Organization/OU=Organization Unit/CN=Client Certificate Name/emailAddress=email@domain.com'
Congratulations!
Add your own comment.