brianc/node-postgres · error · Error

SASL: Only mechanism(s) ${candidates.join(' and ')} are supp

Error message

SASL: Only mechanism(s) ${candidates.join(' and ')} are supported

What it means

Thrown during SCRAM authentication (sasl.js:41-43) when the PostgreSQL server's advertised SASL mechanism list does not include SCRAM-SHA-256 or SCRAM-SHA-256-PLUS. node-postgres only implements the SCRAM-SHA-256 family per RFC 5802/7677; older authentication methods (like SCRAM-SHA-512 or GSSAPI) are not supported. The candidates array is built dynamically: SCRAM-SHA-256-PLUS is added first if a TLS stream with channel-binding support is available, then SCRAM-SHA-256. If the server offers neither, authentication cannot proceed.

Source

Thrown at packages/pg/lib/crypto/sasl.js:42

  // RFC 3454 Table B.1 — "commonly mapped to nothing". The set intentionally
  // contains zero-width joiners and variation selectors — the very characters
  // ESLint's no-misleading-character-class warns about — because they combine
  // with their neighbors and the RFC strips them for that reason.
  // eslint-disable-next-line no-misleading-character-class
  const mappedToNothing = /[\u00AD\u034F\u1806\u180B\u180C\u180D\u200C\u200D\u2060\uFE00-\uFE0F\uFEFF]/g
  return password.replace(nonAsciiSpace, ' ').replace(mappedToNothing, '').normalize('NFKC')
}

const DEFAULT_MAX_SCRAM_ITERATIONS = 100000

function startSession(mechanisms, stream, scramMaxIterations = DEFAULT_MAX_SCRAM_ITERATIONS) {
  const candidates = ['SCRAM-SHA-256']
  if (stream) candidates.unshift('SCRAM-SHA-256-PLUS') // higher-priority, so placed first

  const mechanism = candidates.find((candidate) => mechanisms.includes(candidate))

  if (!mechanism) {
    throw new Error('SASL: Only mechanism(s) ' + candidates.join(' and ') + ' are supported')
  }

  if (mechanism === 'SCRAM-SHA-256-PLUS' && typeof stream.getPeerCertificate !== 'function') {
    // this should never happen if we are really talking to a Postgres server
    throw new Error('SASL: Mechanism SCRAM-SHA-256-PLUS requires a certificate')
  }

  const clientNonce = crypto.randomBytes(18).toString('base64')
  const gs2Header = mechanism === 'SCRAM-SHA-256-PLUS' ? 'p=tls-server-end-point' : stream ? 'y' : 'n'

  return {
    mechanism,
    clientNonce,
    response: gs2Header + ',,n=*,r=' + clientNonce,
    message: 'SASLInitialResponse',
    scramMaxIterations,
  }
}

View on GitHub (pinned to c5e8c9a57b)

Solutions

  1. Ensure the PostgreSQL server supports SCRAM-SHA-256 by setting password_encryption='scram-sha-256' in postgresql.conf and re-setting the user's password.
  2. If connecting through PgBouncer, verify its auth configuration passes through SCRAM-SHA-256.
  3. Upgrade node-postgres to the latest version; if your server only offers scram-sha-512, you may need a driver or server-side change to enable scram-sha-256.

Example fix

-- on the PostgreSQL server
ALTER SYSTEM SET password_encryption = 'scram-sha-256';
SELECT pg_reload_conf();
ALTER ROLE myuser WITH PASSWORD 'mypass'; -- re-hash with new scheme
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await client.connect();
} catch (err) {
  if (/Only mechanism.*SCRAM-SHA-256/i.test(err.message)) {
    console.error('Server does not offer SCRAM-SHA-256. Check password_encryption on the server.');
  }
  throw err;
}

Prevention

When it happens

Trigger: Connecting to a PostgreSQL server configured with password_encryption=scram-sha-512-only or an older server (pre-10) that only offers MD5 or cleartext, but where the auth flow reaches the SASL handler. Also if a proxy or connection pooler (like PgBouncer in certain modes) strips or rewrites the mechanism list.

Common situations: PostgreSQL 18+ defaults to scram-sha-512; if the server is configured to only accept that, this client cannot authenticate. A misconfigured PgBouncer or a man-in-the-middle altering the auth negotiation. Connecting to a non-PostgreSQL server that speaks a different SASL dialect.

Related errors


AI-assisted analysis of brianc/node-postgres@c5e8c9a57b (2026-08-03). Data as JSON: /data/errors/ac5c0cff8e1eb6f5.json. Report an issue: GitHub.