Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

SQL Server JDBC Error on Java 8: The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption

Ask Question

I am getting the following error when connecting to a SQL Server database using version the Microsoft JDBC Driver:

com.microsoft.sqlserver.jdbc.SQLServerException: The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption. Error: "SQL Server returned an incomplete response. The connection has been closed. ClientConnectionId:98d0b6f4-f3ca-4683-939e-7c0a0fca5931".

We recently upgraded our applications from Java 6 & Java 7 to Java 8. All systems running Java are running SUSE Linux Enterprise Server 11 (x86_64), VERSION = 11, PATCHLEVEL = 3.

Here are the facts I have collected with a Java program that I wrote which simply sequentially opens and closes 1,000 database connections.

  • Connections are dropped with this error about 5%-10% of the time. The error DOES NOT occur on every connection.
  • The problem ONLY occurs with Java 8. I ran the same program on Java 7 and the problem is not reproducible. This is consistent with our experience in production prior to upgrading. We've had zero problems running under Java 7 in production.
  • The problem DOES NOT occur on all of our Linux servers running Java 8, it only occurs on some of them. This is perplexing to me, but when I run the same test program on the same version of the Linux JVM (1.8.0_60, 64 bit) on different Linux instances, the problem does not occur on one of the Linux instances, but the problem does occur on others. The Linux instances are running the same version of SUSE and they are at the same patch level.
  • The problem occurs when connecting to BOTH SQL Server 2008 and SQL Server 2014 servers/databases.
  • The problem occurs regardless if I am using the 4.0 version of the SQL Server JDBC driver or the newer 4.1 version of the driver.
  • The thing that makes my observations unique on this compared to others on the web is that although the problem happens ONLY on Java 8, I cannot get the problem to occur on one of the seemingly identical Linux servers that is running the same Java 8 JVM. Other folks have seen this problem on earlier versions of Java as well, but that has not been our experience.

    Any input, suggestions, or observations you may have are appreciated.

    Hello from 2022, this worked for me in JetBrains DataGrip. I have my URL formatted like this jdbc:sqlserver://HOST_GOES_HERE;encrypt=true;trustServerCertificate=true; user18270057 Apr 1, 2022 at 8:30 The solution is seemingly NOT for production, link above clearly states: the Microsoft JDBC Driver for SQL Server won't validate the SQL Server TLS certificate. This setting is common for allowing connections in test environments,... BoomShaka May 31, 2022 at 17:39 For IntelliJ/DataGrip folks, if adding encrypt=true;trustServerCertificate=true; is not working for you, make sure that 'encrypt' and 'trustServerCertificate' are not set to false in the 'advanced' tab jmatias Jun 13, 2022 at 20:22

    I turned on SSL logging in the Java 8 JVM on a Linux instance which reproduces the problem. SSL logging is turned on using -Djavax.net.debug=ssl:handshake:verbose . This revealed some useful information.

    The workaround that we are using in production and has proven to work for us is to set this parameter on the JVM:

     -Djdk.tls.client.protocols=TLSv1
    

    If you want more details, please read on.

    On a server where the problem can be reproduced (again, only 5-10% of the time), I observed the following:

    *** ClientHello, TLSv1.2
    --- 8<-- SNIP -----
    main, WRITE: TLSv1.2 Handshake, length = 195
    main, READ: TLSv1.2 Handshake, length = 1130
    *** ServerHello, TLSv1.2
    --- 8<-- SNIP -----
    %% Initialized:  [Session-79, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256]
    ** TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
    --- 8<-- SNIP -----
    Algorithm: [SHA1withRSA]
    --- 8<-- SNIP -----
    *** Diffie-Hellman ServerKeyExchange
    --- 8<-- SNIP -----
    *** ServerHelloDone
    *** ClientKeyExchange, DH
    --- 8<-- SNIP -----
    main, WRITE: TLSv1.2 Handshake, length = 133
    --- 8<-- SNIP -----
    main, WRITE: TLSv1.2 Change Cipher Spec, length = 1
    *** Finished
    verify_data:  { 108, 116, 29, 115, 13, 26, 154, 198, 17, 125, 114, 166 }
    main, WRITE: TLSv1.2 Handshake, length = 40
    main, called close()
    main, called closeInternal(true)
    main, SEND TLSv1.2 ALERT:  warning, description = close_notify
    main, WRITE: TLSv1.2 Alert, length = 26
    main, called closeSocket(true)
    main, waiting for close_notify or alert: state 5
    main, received EOFException: ignored
    main, called closeInternal(false)
    main, close invoked again; state = 5
    main, handling exception: java.io.IOException: SQL Server returned an incomplete response. The connection has been closed. ClientConnectionId:12a722b3-d61d-4ce4-8319-af049a0a4415
    

    Notice that TLSv1.2 is selected by the database server and used in this exchange. I've observed that, when connections fail from the problematic linux service, TLSv1.2 is ALWAYS the level which was selected. However, connections do not ALWAYS fail when TLSv1.2 is used. They only fail 5-10% of the time.

    Now here is an exchange from a server that does NOT have the problem. Everything else is equal. I.e., connecting to the same database, same version of the JVM (Java 1.8.0_60), same JDBC driver, etc. Notice that, here, TLSv1 is selected by the database server instead of TLSv1.2 as in the faulty server's case.

    *** ClientHello, TLSv1.2
    --- 8<-- SNIP -----
    main, WRITE: TLSv1.2 Handshake, length = 207
    main, READ: TLSv1 Handshake, length = 604
    *** ServerHello, TLSv1
    --- 8<-- SNIP -----
    Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA
    --- 8<-- SNIP -----
    %% Initialized:  [Session-79, TLS_RSA_WITH_AES_128_CBC_SHA]
    ** TLS_RSA_WITH_AES_128_CBC_SHA
    --- 8<-- SNIP -----
    Algorithm: [SHA1withRSA]
    --- 8<-- SNIP -----
    *** ServerHelloDone
    *** ClientKeyExchange, RSA PreMasterSecret, TLSv1
    --- 8<-- SNIP -----
    main, WRITE: TLSv1 Handshake, length = 134
    main, WRITE: TLSv1 Change Cipher Spec, length = 1
    *** Finished
    verify_data:  { 26, 155, 166, 89, 229, 193, 126, 39, 103, 206, 126, 21 }
    main, WRITE: TLSv1 Handshake, length = 48
    main, READ: TLSv1 Change Cipher Spec, length = 1
    main, READ: TLSv1 Handshake, length = 48
    *** Finished
    

    So, when TLSv1 is negotiated between the Linux JVM and the SQL Server, connections are ALWAYS successful. When TLSv1.2 is negotiated, we get sporadic connection failures.

    (Note: Java 7 (1.7.0_51) always negotiates TLSv1, which is why the problem never occurred for us with a Java 7 JVM.)

    The open questions we still have are:

  • WHY is that the same Java 8 JVM run from 2 different Linux servers will always negotiate TLSv1, but when connecting from another Linux server it always negotiates TLSv1.2.
  • And also why are TLSv1.2 negotiated connections successful most, but not all, of the time on that server?
  • Update 6/10/2017: This posting from Microsoft describes the problem and their proposed solution.

    Resources:

    http://www.infoworld.com/article/2849292/operating-systems/more-patch-problems-reported-with-the-ms14-066-kb-2992611-winshock-mess.html

    http://www.infoworld.com/article/2849292/operating-systems/more-patch-problems-reported-with-the-ms14-066-kb-2992611-winshock-mess.html

    http://blogs.msdn.com/b/jdbcteam/archive/2008/09/09/the-driver-could-not-establish-a-secure-connection-to-sql-server-by-using-secure-sockets-layer-ssl-encryption.aspx

    Java 8 , JCE Unlimited Strength Policy and SSL Handshake over TLS

    http://blogs.msdn.com/b/saponsqlserver/archive/2013/05/10/analyzing-jdbc-connection-issues.aspx

    https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#descPhase2

    https://blogs.oracle.com/java-platform-group/entry/java_8_will_use_tls

    In case someone arrives here looking for a solution to connect to a database from PhpStorm, just add the following after the port in the URL:

    ;encrypt=true;trustServerCertificate=true;
    

    I got the solution from this comment: SQL Server JDBC Error on Java 8: The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption

    Thank you so much! Can confirm it's working on PhpStorm 2022.1.1.

    Using openjdk 11 it's possible to add the following properties to the connection URL in order to force the use of SSL

    ;integratedSecurity=false;encrypt=false;trustServerCertificate=true;

    Add ;encrypt=true;trustServerCertificate=true into connection.url. Example

    jdbc:sqlserver://localhost\SQLEXPRESS:1433;databaseName=testdb;encrypt=true;trustServerCertificate=true

    And check Compatible compiler version java in pom file with version jre of mssql-jdbc of maven. Like this

    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    
    <dependency>
        <groupId>com.microsoft.sqlserver</groupId>
        <artifactId>mssql-jdbc</artifactId>
        <version>11.2.1.jre8</version>
    </dependency>
    

    compiler 1.8 and jre8

  • Sqljdbc.jar requires a JRE of 5 and supports the JDBC 3.0 API
  • Sqljdbc4.jar requires a JRE of 6 and supports the JDBC 4.0 API
  • Sqljdbc41.jar requires a JRE of 7 and supports the JDBC 4.1 API
  • Sqljdbc42.jar requires a JRE of 8 and supports the JDBC 4.2 API
  • Source: https://www.microsoft.com/en-us/download/details.aspx?id=11774

    Upgraded jvm version to Java 1.8 and this is when I started to see the issue. Upgrading the driver did not help in my case. – Wojciech Jakubas Nov 23, 2021 at 14:08

    This appears to have been fixed in version 4.2 of the MS SQL JDBC driver. I created a program where I connected to the server 1000 times, pausing 100ms between each attempt. With version 4.1 I was able to reproduce the problem every time, although it happened only sporadically. With version 4.2 I was unable to reproduce the problem.

    That is good information. However, the version 4.2 driver does not work under Java 7 (at least last I checked about a month ago). Microsoft claims it is compatible with Java 6, 7 & 8, but they apparently compiled the driver code with a Java 8 compiler. In our mixed environment of running Java 7 and Java 8, we are unable to run the 4.2 driver due to this problem. See social.msdn.microsoft.com/Forums/en-US/… – 2Aguy Sep 30, 2015 at 14:30
  • application.properties:
  •     spring.datasource.url=jdbc:sqlserver://<YourServerName>:1433;database=<YourDatabaseName>;encrypt=true;trustServerCertificate=true;
        spring.datasource.username=root
        spring.datasource.password=1234
        spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
        spring.jpa.show-sql=true
        spring.jpa.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
        spring.jpa.properties.hibernate.globally_quoted_identifiers=true
        spring.jpa.hibernate.ddl-auto = create-drop
    

    Issue got resolved for me when I changed the sqljdbc-4.2.0 jar with mssql-jdbc-8.4.1 jar

    <dependency>
          <groupId>com.microsoft.sqlserver</groupId>
          <artifactId>mssql-jdbc</artifactId>
          <version>8.4.1.jre8</version>
    </dependency>
                    Changed my POM from the autogenerated code from spring to the above posted code and it really solved the problem after a LONG search. I don't know how and why, but it does. +1
    – Killgnom
                    Jul 11, 2022 at 11:47
    

    In my case i had a sql server using the 3DES_EDE_CBC algorithm, this is disabled by default on jdk 1.8 , so checking the

    /Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/security/java.security

    And eliminating the algorithm from:

    jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, DH keySize < 1024, \ EC keySize < 224, 3DES_EDE_CBC, anon, NULL

    Worked for me.

    This solved the problem in my case, too. I have tried some of the other hints in this thread, but nothing worked. I guess, it depends on the encryption algorithm used by the server. In my case it was a rather old instance of SQL Server 2005. – gemue Sep 10, 2019 at 7:46

    Like @2Aguy wrote, you can change the JVM parameter. In my case I couldn't change it, and used the connection string "sslProtocol" parameter, lowering the connection to TLSV1.

    Connection String: jdbc:sqlserver://<HOST>:<PORT>;encrypt=true;trustServerCertificate=true;sslProtocol=TLSv1;database=<DB NAME>

    I missed this one, so didnt try it, but I was finding that encrypt=false wasn't working at all, so a way to force TLSv1 was required. I did it in a more heavy-handed way by disabling the disabling of TLSv1 in /usr/lib/jvm/java-11-openjdk-amd64/conf/security/java.security. This option may have been better – Auspex Dec 20, 2022 at 22:09

    Thanks to @Sunil Kumar and @Joce. I used the jar and below syntax:

    String myDriver = "com.microsoft.jdbc.sqlserver.SQLServerDriver";

    String myURL = "jdbc:sqlserver://DB_ipaddress\DB_instance;databaseName=DB_name;user=myusername; password=mypass;encrypt=true;trustServerCertificate=true;"; /==> here the semicolon will be twice like shown/

    Connection con = DriverManager.getConnection(myURL);

    As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center. – Community Apr 7, 2022 at 23:03

    Microsoft Recently open sourced their driver. One can see mssql-jdbc driver activity on GitHub. I guess latest preview version is 6.1.5.

    Also you can find all preview versions on maven too. Supporting both JDK7 & JDK 8.

    In my case, the issue was because the app was set to use spring-boot-ext-security-starter-credhub-credential and there were some issues with that setup.

    So I removed credhub from the manifest file and pom and fetched credentials in a different way; then the error was gone.

    If the server name in the connection string does not match the server name in the SQL Server SSL certificate, the following error will be issued: The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption. Error: "java.security.cert.CertificateException: Failed to validate the server name in a certificate during Secure Sockets Layer (SSL) initialization."

    This helped me resolve the issue. Was using the localhost in servername, finally changing in jdbc connection string to the same name as the CN was able to connect.

    Refer: https://wiki.deepnetsecurity.com/pages/viewpage.action?pageId=1410867 for more info

    I have fixed the issue on my local enviroment, it mainly contains two steps below.

  • Switch the JDBC Driver dependency like below if your project is built by maven:
  • <dependency>
      <groupId>net.sourceforge.jtds</groupId>
      <artifactId>jtds</artifactId>
      <version>1.3.1</version>
    </dependency>
    

    2.Replace the Driver Class Name additionally:

    ru.yandex.clickhouse.ClickHouseDriver
    

    3.Modify the JDBC URL like this:

    jdbc:jtds:sqlserver://xxxx:1433;databaseName=xxx
    

    I have faced this issue while connecting SQL database. Faced this issue because of incorrect JAR file.

    Connection URL that I used

     "jdbc:sqlserver://localhost:8080;databaseName=db_name;encrypt=true;trustServerCertificate=true";
    

    Before I used "sqljdbc4-2.0.jar" JAR file, it won't work for me.

    Once I changed this JAR file then it worked fine

    mssql-jdbc-8.4.1.jre8.jar

    I had this issue recently after doing a yum update in a client's server running RedHat 7. Since the above thread did not help me resolve my issue, I am posting this answer.

    Issue:- Yum update in RedHat automatically reinstalls OpenJDK , my applications use oracle JDK. Verifying Default JDK:

    java version Switch the default version:

    update-alternatives --config java

    There are 2 programs which provide 'java'.

    Selection Command

  • 1 java-1.8.0-openjdk.x86_64 (/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.302.b08-0.el7_9.x86_64/jre/bin/java)
  • 2 /usr/java/jdk1.8.0_181-amd64/jre/bin/java
  • Enter to keep the current selection[+], or type selection number:

    Enter the number alongside the appropriate version you want to us and hit enter.

    I have also faced same issue while creating connection to the database with below connection string.

    DriverManager.getConnection("jdbc:sqlserver://" + host + ":" + port + ";databaseName=" + dbName + ";user=" + userName + ";password=" + password);
    

    After updating connection string as below, it worked.

    Connection con = DriverManager.getConnection("jdbc:sqlserver://" + host + ":" + port + ";databaseName=" + dbName + ";encrypt=true;trustServerCertificate=true;user=" + userName + ";password=" + password);
    

    here i have added encrypt=true;trustServerCertificate=true after the database name.

    For me I add to add Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); between the two lines

    DriverManager.registerDriver(new com.microsoft.sqlserver.jdbc.SQLServerDriver());

    Connection con = DriverManager.getConnection(connectionUrl);

    So the final code for the connection would be:

        DriverManager.registerDriver(new com.microsoft.sqlserver.jdbc.SQLServerDriver());
        Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
        Connection con = DriverManager.getConnection(connectionUrl);
    

    If you came here for Ignition 8.1+ error, and you're using MSSQL express on your local host, at your "Connect URL" put this: jdbc:sqlserver://localhost\SQLEXPRESS; encrypt=true;trustServerCertificate=true; URL settings

    Valid connection

    SQL connectivity exceptions - The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption See more linked questions