Skip to content

Add support for sslnegotiation=direct (PostgreSQL 17)#3688

Open
Shion1305 wants to merge 1 commit into
brianc:masterfrom
Shion1305:feat/sslnegotiation-direct
Open

Add support for sslnegotiation=direct (PostgreSQL 17)#3688
Shion1305 wants to merge 1 commit into
brianc:masterfrom
Shion1305:feat/sslnegotiation-direct

Conversation

@Shion1305
Copy link
Copy Markdown

@Shion1305 Shion1305 commented Jun 3, 2026

Adds support for PostgreSQL 17's sslnegotiation connection parameter. The default, postgres, keeps the existing behavior: the driver sends an SSLRequest packet and waits for the server's S/N reply before starting the TLS handshake. The new direct value starts the TLS handshake immediately after the TCP connection is established, saving a network round-trip and allowing protocol-agnostic TLS tooling. As in libpq, direct advertises the postgresql ALPN protocol during the handshake and requires SSL to be enabled.

Usage mirrors the existing ssl options — via config object, PGSSLNEGOTIATION, or connection string:

new Client({ host, ssl: { rejectUnauthorized: false }, sslnegotiation: 'direct' })
new Client('postgres://user:pw@host/db?sslmode=require&sslnegotiation=direct')

Closes #3346.


A few design notes:

  • direct requires SSL to be enabled (ConnectionParameters throws otherwise), matching libpq's rule that direct negotiation is only allowed with sslmode=require or higher so there's no silent plaintext fallback. In a connection string, sslnegotiation=direct enables SSL automatically when no other SSL option is present.
  • The TLS upgrade in connection.js was extracted into upgradeToSSL() so both negotiation styles share it; only the direct path skips the SSLRequest/S-byte exchange and sets ALPNProtocols.
  • sslnegotiation is also added to the libpq connection string for the native (pg-native) path.
  • Tests cover connection-string parsing, ConnectionParameters validation, and the connection behavior itself (no SSLRequest packet is written in direct mode, and ALPN is set only for direct). I followed pgjdbc/libpq for the parameter semantics.

I've verified this against a personal PostgreSQL 17.5 instance configured to require direct SSL. With sslnegotiation=direct, the client establishes TLS 1.3, negotiates the postgresql ALPN protocol, and runs queries successfully; pg_stat_ssl confirms the connection is encrypted server-side. The same server rejects the traditional sslnegotiation=postgres handshake with ECONNRESET, confirming the two negotiation styles take genuinely different code paths.

PostgreSQL 17 added the `sslnegotiation` connection parameter, which
allows clients to start the TLS handshake immediately after the TCP
connection ("direct" negotiation) instead of first sending an SSLRequest
packet and waiting for the server's S/N reply ("postgres" negotiation,
the default and prior behavior). Direct negotiation saves one network
round-trip and works with protocol-agnostic TLS tooling.

- connection.js: extract the TLS upgrade into upgradeToSSL(); in direct
  mode upgrade the socket right after connect (skipping the SSLRequest
  exchange) and advertise the `postgresql` ALPN protocol as the server
  requires.
- client.js: forward sslNegotiation to the Connection and skip
  requestSsl() in direct mode.
- connection-parameters.js: read sslnegotiation from config /
  PGSSLNEGOTIATION, validate it is `postgres` or `direct`, require SSL to
  be enabled for `direct`, and include it in the libpq connection string.
- pg-connection-string: parse the sslnegotiation query param and enable
  SSL automatically when `direct` is requested without other SSL config.
- docs: document the new option.
- tests: cover connection-string parsing, connection-parameters
  validation, and the direct-vs-traditional connection behavior
  (no SSLRequest packet, ALPN set only for direct).

Closes brianc#3346
@Shion1305 Shion1305 requested a review from hjr3 as a code owner June 3, 2026 20:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

support PG 17 sslnegotiation=direct

1 participant