node-postgres supports TLS/SSL connections to your PostgreSQL server as long as the server is configured to support it. When instantiating a pool or a client you can provide an ssl property on the config object and it will be passed to the constructor for the node TLSSocket.

Self-signed cert

Here’s an example of a configuration you can use to connect a client or a pool to a PostgreSQL server.

const config = {
  database: 'database-name',
  host: 'host-or-ip',
  // this object will be passed to the TLSSocket constructor
  ssl: {
    ca: fs.readFileSync('/path/to/server-certificates/root.crt'),
    key: fs.readFileSync('/path/to/client-key/postgresql.key'),
    cert: fs.readFileSync('/path/to/client-certificates/postgresql.crt'),
  },
}
 
import { Client, Pool } from 'pg'
 
const client = new Client(config)
await client.connect()
console.log('connected')
await client.end()
 
const pool = new Pool(config)
const pooledClient = await pool.connect()
console.log('connected')
pooledClient.release()
await pool.end()

Usage with connectionString

If you plan to use a combination of a database connection string from the environment and SSL settings in the config object directly, then you must avoid including any of sslcert, sslkey, sslrootcert, or sslmode in the connection string. If any of these options are used then the ssl object is replaced and any additional options provided there will be lost.

const config = {
  connectionString: 'postgres://user:password@host:port/db?sslmode=require',
  // Beware! The ssl object is overwritten when parsing the connectionString
  ssl: {
    ca: fs.readFileSync('/path/to/server-certificates/root.crt'),
  },
}

Direct SSL negotiation

By default node-postgres uses the traditional PostgreSQL SSL negotiation: it sends an SSLRequest packet, waits for the server to acknowledge it, and only then starts the TLS handshake. PostgreSQL 17 and newer also support direct SSL negotiation, where the TLS handshake begins immediately on connect (similar to HTTPS), saving one network round-trip.

To use direct negotiation, set sslnegotiation: 'direct'. SSL must be enabled, and the server must be PostgreSQL 17+ configured to accept direct SSL connections.

const config = {
  database: 'database-name',
  host: 'host-or-ip',
  ssl: { rejectUnauthorized: false },
  sslnegotiation: 'direct',
}

It can also be supplied via a connection string. When sslnegotiation=direct is present, SSL is enabled automatically if not otherwise configured:

const config = {
  connectionString: 'postgres://user:password@host:port/db?sslmode=require&sslnegotiation=direct',
}

Direct negotiation requests the postgresql ALPN protocol during the TLS handshake, as required by the server. The default value is 'postgres', which preserves the traditional SSLRequest behavior. You can also set the PGSSLNEGOTIATION environment variable.

Channel binding

If the PostgreSQL server offers SCRAM-SHA-256-PLUS (i.e. channel binding) for TLS/SSL connections, you can enable this as follows:

const client = new Client({ ...config, enableChannelBinding: true})

or

const pool = new Pool({ ...config, enableChannelBinding: true})