I need to configure TLS 1.1 protocol for SSL connection in PostgreSQL.

I was not able to see protocol setting in the PostgreSQL configuration

It is required to disable SSL protocols and TLSv1 and enable only TLSv1.1 (or TLSv1.2)


PCI DSS v3.1 requires that fallback to SSL and TLSv1 will be disabled.

Is it is possible to configure PostgreSQL to negotiate using TLSv1.1 only?

If you know that it is impossible please share this information

Added 2

Unfortunately, the configuration of ssl_ciphers is not enough since you can use same ciphers for different protocols. It is required to configure SSL_METHOD as described here: https://www.openssl.org/docs/manmaster/ssl/ssl.html.

My conclusion that the configuration of SSL_METHOD (or SSL_PROTOCOL) is missed from the PostgreSQL configuration and it can not be complaint to PCI DSS 3.1.

Please correct me if I am wrong.

  • 5
    Tom says: "libpq versions before 9.4 will only accept TLSv1 exactly. In 9.4 it should negotiate the highest TLS version supported by both server and client." So you might be out of luck on 9.1. Sep 18 '15 at 14:04
  • Is upgrading to 9.3 (preferably 9.4) an option?
    – dezso
    Oct 1 '15 at 8:19
  • @dezso I have changed my question to version 9.4. Any case, I did not find in the configuration option to configure TLS 1.1 protocol for SSL connection.
    – Michael
    Oct 1 '15 at 10:07

Meanwhile, starting from Postgres 12, it's possible to force the minimal SSL/TLS encryption level at the server side by tweaking the ssl_min_protocol_version` parameter.

According to this documentation page valid values are currently: TLSv1, TLSv1.1, TLSv1.2, TLSv1.3.


@BrianEfting was correct, you can specify the appropriate cipher suites to only allow TLSv1.2 which should fit your PCI-DSS 3.1 specification needs.

Using a cipher list like this in the ssl_ciphers option in your postgresql.conf:


along with setting ssl_prefer_server_ciphers=true, should be sufficient to allow only TLSv1.2 connections.

You can verify this using SSLyze which knows about the PostgreSQL protocol.

To test, I used the following command:

./sslyze.py --sslv2 --sslv3 --tlsv1 --tlsv1_1 --tlsv1_2 localhost:5432 --starttls=postgres --hide_rejected_ciphers

Which gave the output below under PostgreSQL 9.4 on Debian Wheezy showing that all cipher suites except for the TLSv1.2 ciphers specified were rejected, which should satisfy the requirements of PCI-DSS 3.1 by using TLSv1.1 or greater.

postgres@pgsqlsec4:~/sslyze$ ./sslyze.py --sslv2 --sslv3 --tlsv1 --tlsv1_1 --tlsv1_2 localhost:5432 --starttls=postgres --hide_rejected_ciphers




   localhost:5432                      => ::1:5432


  * SSLV2 Cipher Suites:
      Server rejected all cipher suites.

  * TLSV1_2 Cipher Suites:
                 ECDHE-RSA-AES128-GCM-SHA256   ECDH-256 bits  128 bits                                         
                 ECDHE-RSA-AES256-SHA384       ECDH-256 bits  256 bits                                         
                 ECDHE-RSA-AES256-GCM-SHA384   ECDH-256 bits  256 bits                                         
                 DHE-RSA-AES256-SHA256         DH-1024 bits   256 bits                                         
                 DHE-RSA-AES256-GCM-SHA384     DH-1024 bits   256 bits                                         
                 ECDHE-RSA-AES128-SHA256       ECDH-256 bits  128 bits                                         
                 ECDHE-RSA-AES128-GCM-SHA256   ECDH-256 bits  128 bits                                         
                 DHE-RSA-AES128-SHA256         DH-1024 bits   128 bits                                         
                 DHE-RSA-AES128-GCM-SHA256     DH-1024 bits   128 bits                                         

  * TLSV1_1 Cipher Suites:
      Server rejected all cipher suites.

  * TLSV1 Cipher Suites:
      Server rejected all cipher suites.

  * SSLV3 Cipher Suites:
      Server rejected all cipher suites.

  • It is the workaround. Once again: it is required to configure protocol and it is missed from PostgreSQL configuration. I can not accept the answer. Any case, I do not have a problem to give a bounty for the hard work.
    – Michael
    Oct 6 '15 at 11:13
  • @Michael This is functionally identical to disabling TLS v1.0. There is a new config directive in version 12 of Postgres but it's not been released yet: ssl_min_protocol_version=TLSv1.1
    – deed02392
    Sep 5 '19 at 16:11
  • It's not functionally identical is the problem: It also disables TLS 1.1 because there are no new cipher suites there. It's also far less auditable, though arguably that's not a functional aspect. You could make it slightly more auditable by tacking on a !TLSv1. but still compare that to an nginx config for example, where an auditor only has to read a single one or two word line.
    – DylanYoung
    Jun 4 '20 at 17:02

From the following link:

18.3. Connections and Authentication (PostgreSQL 9.4 Manual)

It would appear that you can use the ssl_ciphers option to specify your list of accepted ciphers. And it mentions that it follows whatever your version of OpenSSL supports.

And in this link:

OpenSSL Ciphers (OpenSSL.org)

Mentions that there is no specific ciphersuite for TLSv1.1 but you can specify TLSv1.2.

  • Unfortunately, the configuration of ssl_ciphers is not enough since you can use same ciphers for different protocols. It is required to configure SSL_METHOD as described here: openssl.org/docs/manmaster/ssl/ssl.html. My conclusion that the configuration of SSL_METHOD (or SSL_PROTOCOL) is missed from the PostgreSQL configuration and it can not be complaint to PCI DSS 3.1. Please correct me if I am wrong.
    – Michael
    Oct 4 '15 at 8:23
  • Well thank you Michael. I think @Kassandry worked harder than I did, though, and deserves some serious props here. Even going so far as to test and see that the insecure methods are indeed rejected. Oct 7 '15 at 18:12
  • Yes, but you was the first with this approach. Unfortunately, I can not spit the bounty
    – Michael
    Oct 8 '15 at 10:14

You can specify the protocols (TLSv1.2) instead of fine grained list of ciphers in the conf file.


Modify postgresql.conf

ssl_ciphers = 'TLSv1.2:!aNULL'

Restart the service

/etc/init.d/postgresql94 restart

Re-run the test again

sslyze  --sslv2 --sslv3 --tlsv1 --tlsv1_1 --tlsv1_2 localhost:5432 --starttls=postgres --hide_rejected_ciphers

This should do it if you're using the defaults to start:

ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL:!SSLv3'

It also covers TLS1.1, TLS1.0, and SSLv2 on newer versions of openssl. (See the postgresql docs for info on the +3DES hack; it does appear to have been fixed in newer versions of openssl).

If not or if you want to be more explicit, just append, ':!SSLv2:!SSLv3:!TLSv1'

TLSv1.1 is also deprecated, so I recommend also appending ':!TLSv1.1'

This gives a final "safe" cipher string based on the default as follows: HIGH:MEDIUM:+3DES:!aNULL:!SSLv2:!SSLv3:!TLSv1:!TLSv1.1

You can test with your version of openssl using the following:

openssl ciphers -v MY_CIPHER_STRING | column -t

This is lists all the ciphers that will be included WITH their protocol.

Sample output with the "safe" ciphers list above (opensslv1.0.1):

ECDHE-RSA-AES256-GCM-SHA384    TLSv1.2  Kx=ECDH        Au=RSA    Enc=AESGCM(256)  Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384  TLSv1.2  Kx=ECDH        Au=ECDSA  Enc=AESGCM(256)  Mac=AEAD
ECDHE-RSA-AES256-SHA384        TLSv1.2  Kx=ECDH        Au=RSA    Enc=AES(256)     Mac=SHA384
ECDHE-ECDSA-AES256-SHA384      TLSv1.2  Kx=ECDH        Au=ECDSA  Enc=AES(256)     Mac=SHA384
DHE-DSS-AES256-GCM-SHA384      TLSv1.2  Kx=DH          Au=DSS    Enc=AESGCM(256)  Mac=AEAD
DHE-RSA-AES256-GCM-SHA384      TLSv1.2  Kx=DH          Au=RSA    Enc=AESGCM(256)  Mac=AEAD
DHE-RSA-AES256-SHA256          TLSv1.2  Kx=DH          Au=RSA    Enc=AES(256)     Mac=SHA256
DHE-DSS-AES256-SHA256          TLSv1.2  Kx=DH          Au=DSS    Enc=AES(256)     Mac=SHA256
ECDH-RSA-AES256-GCM-SHA384     TLSv1.2  Kx=ECDH/RSA    Au=ECDH   Enc=AESGCM(256)  Mac=AEAD
ECDH-RSA-AES256-SHA384         TLSv1.2  Kx=ECDH/RSA    Au=ECDH   Enc=AES(256)     Mac=SHA384
ECDH-ECDSA-AES256-SHA384       TLSv1.2  Kx=ECDH/ECDSA  Au=ECDH   Enc=AES(256)     Mac=SHA384
AES256-GCM-SHA384              TLSv1.2  Kx=RSA         Au=RSA    Enc=AESGCM(256)  Mac=AEAD
AES256-SHA256                  TLSv1.2  Kx=RSA         Au=RSA    Enc=AES(256)     Mac=SHA256
ECDHE-RSA-AES128-GCM-SHA256    TLSv1.2  Kx=ECDH        Au=RSA    Enc=AESGCM(128)  Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256  TLSv1.2  Kx=ECDH        Au=ECDSA  Enc=AESGCM(128)  Mac=AEAD
ECDHE-RSA-AES128-SHA256        TLSv1.2  Kx=ECDH        Au=RSA    Enc=AES(128)     Mac=SHA256
ECDHE-ECDSA-AES128-SHA256      TLSv1.2  Kx=ECDH        Au=ECDSA  Enc=AES(128)     Mac=SHA256
DHE-DSS-AES128-GCM-SHA256      TLSv1.2  Kx=DH          Au=DSS    Enc=AESGCM(128)  Mac=AEAD
DHE-RSA-AES128-GCM-SHA256      TLSv1.2  Kx=DH          Au=RSA    Enc=AESGCM(128)  Mac=AEAD
DHE-RSA-AES128-SHA256          TLSv1.2  Kx=DH          Au=RSA    Enc=AES(128)     Mac=SHA256
DHE-DSS-AES128-SHA256          TLSv1.2  Kx=DH          Au=DSS    Enc=AES(128)     Mac=SHA256
ECDH-RSA-AES128-GCM-SHA256     TLSv1.2  Kx=ECDH/RSA    Au=ECDH   Enc=AESGCM(128)  Mac=AEAD
ECDH-RSA-AES128-SHA256         TLSv1.2  Kx=ECDH/RSA    Au=ECDH   Enc=AES(128)     Mac=SHA256
ECDH-ECDSA-AES128-SHA256       TLSv1.2  Kx=ECDH/ECDSA  Au=ECDH   Enc=AES(128)     Mac=SHA256
AES128-GCM-SHA256              TLSv1.2  Kx=RSA         Au=RSA    Enc=AESGCM(128)  Mac=AEAD
AES128-SHA256                  TLSv1.2  Kx=RSA         Au=RSA    Enc=AES(128)     Mac=SHA256


The cipher suite SSLv3 (likewise TLSv1, etc...) expands to all ciphers supported by SSLv3. This means that these same ciphers will be excluded in higher protocols as well (if they exist there).

To demonstrate:

openssl ciphers 'TLSv1:!SSLv3'


Error in cipher list
139740792764064:error:1410D0B9:SSL routines:SSL_CTX_set_cipher_list:no cipher match:ssl_lib.c:1312:

i.e. since every cipher available in SSLv3 is also available in TLSv1, we get no ciphers returned.

As noted by the OP, this means there is no way to disable SSLv3 through the cipher list without also excluding the same cipher for higher protocols

In practice, this should only lead to better security, but it may cause problems for those with backwards compatibility requirements (must support TLSv1.0 and cannot support SSLv3, for example)

Since TLSv1.1 doesn't contain any new ciphers, it will also be disabled if you use !SSLv3.

Be careful!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.