PG18 Hacktober: 31 Days of New Features : Richer SSL/TLS configuration options in PostgreSQL

We’re just into the 4th day of PG18 Hacktober and we’re amazed at the security features that were added in PG18, no wonder PostgreSQL is The World’s Most Advanced Open Source Relational Database and one of the most vibrant FOSS communities.

Here’s our 2nd blog on the Security features focussing on granular SSL/TLS Cipher Suite Configuration for TLS 1.3. If you haven’t read our first blog post on “Secure Password Hashing” it’s available here.

PostgreSQL has supported SSL/TLS encryption for over two decades, providing essential data-in-transit protection for both local and remote connections. But historically, fine-grained control over cipher suites—especially for newer TLS versions—was limited.

With PostgreSQL 18, administrators now gain explicit control over the cipher suites used in TLS 1.3 connections via the new parameter: ssl_tls13_ciphers

This feature gives you the ability to tighten, audit, and tune the cryptographic protocols your server uses—a must-have for organizations under compliance mandates or operating in zero-trust environments.

Going down the memory lane

Here’s how PostgreSQL’s SSL/TLS configuration has evolved over recent major releases:

PG versionSSL SupportNotable Enhancements
10YesBasic support via OpenSSL; cipher configuration only for pre-TLS 1.3
12Yesssl_min_protocol_version and ssl_max_protocol_version added
13YesTLS 1.3 support introduced (via OpenSSL 1.1.1+)
15YesCert authentication improvements (e.g., sslcertmode)
18YesNew ssl_tls13_ciphers setting for granular TLS 1.3 cipher control

What does the documentation say:

ssl_tls13_ciphers (string) specifies a list of cipher suites that are allowed by connections using TLS version 1.3. Multiple cipher suites can be specified by using a colon separated list. If left blank, the default set of cipher suites in OpenSSL will be used.

This parameter can only be set in the postgresql.conf file or on the server command line.
You can define:

  1. Cipher order of preference
  2. Cipher inclusion/exclusion
  3. Alignment with your organization’s crypto policies

Default value:
If unset, the default list includes:
TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
These are all modern, AEAD ciphers considered secure and performant.

Why this matters:

  • Compliance & Audit readiness: Fine-tuning TLS behavior is often a hard requirement for PCI-DSS, HIPAA, FIPS 140-3, and ISO 27001 frameworks.
  • Defense-in-depth: Even with TLS 1.3, not all ciphers are equal. Prioritizing strong and auditable suites minimizes long-term exposure to cryptographic downgrade or side-channel attacks.
  •  Client compatibility: Not all clients support every TLS 1.3 cipher suite. Having control lets you strike the right balance between security and compatibility.

What parameter values to set?

It is important to know how to combine with Other TLS Settings. Use the following for a hardened PostgreSQL SSL/TLS configuration:

ssl = on
ssl_min_protocol_version = 'TLSv1.2'
ssl_max_protocol_version = 'TLSv1.3'
ssl_ciphers = 'HIGH:!aNULL:!MD5'
ssl_tls13_ciphers = 'TLS_AES_256_GCM_SHA384'

Don’t forget to configure your certificates (ssl_cert_file, ssl_key_file,ssl_ca_file) properly for full TLS enforcement.

[postgres@ip-172-31-11-103 ~]$ openssl s_client -starttls postgres -connect 127.0.0.1:5432 -tls1_3
Connecting to 127.0.0.1
CONNECTED(00000003)
Can't use SSL_get_servername
depth=0 CN=localhost
verify error:num=18:self-signed certificate
verify return:1
depth=0 CN=localhost
verify return:1
---
Certificate chain
 0 s:CN=localhost
   i:CN=localhost
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: Oct  4 08:06:34 2025 GMT; NotAfter: Oct  4 08:06:34 2026 GMT
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIDCTCCAfGgAwIBAgIUcT6PuH9qFAXIvanqRmpUgT42bkowDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI1MTAwNDA4MDYzNFoXDTI2MTAw
NDA4MDYzNFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAtaAIPAQGifvaKliqcbtXeEU4x3QfKiLZ8Lf09t05w1h0
1dz6rXXaPmiHUkamjGLvbRVdVEZOs6VmTE0uQ0P1I2/SDKFb87WQrYObz4GhmQkJ
lXIc8wbn4Qnqu0m4YahPva4A1vYhw/0syR7g9WRV4C4Dt7qOXn6q3Hor8w7AqxJA
vpIiuXwiDt2CHKd1+gCi2iDqHHa8EKm3F3NxgLHncQAAfx9S1u2bDf7WewblRlkD
Cz0PEZJd01pcmPLTgcgsXNwcBPphlOfRiGEKu7hx0z7tEoZl+GXhYDbgCY6iAjq/
/DYnoEYQdccUrADMB+4bgDgRYiBCd+nDcyO39ELr5wIDAQABo1MwUTAdBgNVHQ4E
FgQU7CVHOkZ2YdXqA4aiPApvmUogFR0wHwYDVR0jBBgwFoAU7CVHOkZ2YdXqA4ai
PApvmUogFR0wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAdnxp
t7+Az6lwFnCGbRXoMiqrHSAZdw+3muKaYM4w8nvjg5MepY79R2P3BUVJdDOZ7Xxj
tCk3daKZcjg+3zRoDONLQFh0UMMvxEX92d9MXEUfidfXXpMU5f8Q/UnQXAYw1YMq
qMhTNwlhD4N3vIhUR77w3WmwLx3JTZl4GdvF69hFrScMMP7+XrQuVAxQlGdgsGD6
u/M0Jr5gAX9hcw/9IIdG1qhus+w7q9siEf7lPI4zVXkZR8CxeRYELKSiy6MhGegM
deVAP5FKnBejUIfoQ4/3Ui2O6OAfdfD0SzsgrvrkLmN1z11ZAHtbu+vh+ahIKGXc
G95i6U4VLLZtddTM4Q==
-----END CERTIFICATE-----
subject=CN=localhost
issuer=CN=localhost
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 1338 bytes and written 320 bytes
Verification error: self-signed certificate
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
This TLS version forbids renegotiation.
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 18 (self-signed certificate)
---

The above OpenSSL client output demonstrates a successful TLS 1.3 handshake with the PostgreSQL server, using the explicitly configured cipher suite TLS_AES_256_GCM_SHA384. The server presents its certificate, which is self-signed and identified by the common name “localhost.” Although the self-signed certificate triggers a verification warning, this is expected in development or testing environments.If it is a production environment, Replace the self-signed cert with a CA-signed certificate. Importantly, the connection establishes strong encryption with a 2048-bit RSA public key and uses modern, secure cryptographic algorithms as configured. This confirms that PostgreSQL 18’s granular TLS 1.3 cipher suite setting is functioning correctly, enabling administrators to enforce specific, secure ciphers while maintaining encrypted client-server communication. Let’s check the connection using psql.

[postgres@ip-172-31-11-103 ~]$ psql "host=localhost dbname=postgres sslmode=require"
psql (18.0)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off, ALPN: postgresql)
Type "help" for help.

postgres=# \conninfo
            Connection Information
      Parameter       |         Value
----------------------+------------------------
 Database             | postgres
 Client User          | postgres
 Host                 | localhost
 Host Address         | ::1
 Server Port          | 5432
 Options              |
 Protocol Version     | 3.0
 Password Used        | false
 GSSAPI Authenticated | false
 Backend PID          | 13413
 SSL Connection       | true
 SSL Library          | OpenSSL
 SSL Protocol         | TLSv1.3
 SSL Key Bits         | 256
 SSL Cipher           | TLS_AES_256_GCM_SHA384
 SSL Compression      | false
 ALPN                 | postgresql
 Superuser            | on
 Hot Standby          | off
(19 rows)

\conninfo command confirms critical SSL details including the OpenSSL library, protocol version, and cipher in use, ensuring strong encryption. This validates that PostgreSQL’s granular TLS 1.3 cipher configuration is effectively protecting the data in transit while maintaining compatibility with standard PostgreSQL clients.

Final thoughts

PostgreSQL 18’s new TLS cipher configuration might seem like a small addition, but it represents a significant shift toward giving administrators deeper control over cryptographic security. For teams operating in secure, regulated, or high-assurance environments, this change makes PostgreSQL a more adaptable, policy-compliant database engine.

Next up in our security-focused series:
Enhanced SCRAM authentication – more control, more compatibility

We’ll explore the new SCRAM features in PostgreSQL 18 that improve integration with LDAP, SSO, and modern password authentication. Stay tuned!

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top