jackc/pgx · error
no peer certificates for channel binding
Error message
no peer certificates for channel binding
What it means
Returned by getTLSCertificateHash when the TLS connection state has zero peer certificates. Channel binding via tls-server-end-point requires the server's leaf certificate to hash; with no certificate present, the hash cannot be computed. This is an internal error surfaced when channel binding is attempted over an anonymous or PSK TLS session.
Source
Thrown at pgconn/auth_scram.go:381
buf := make([]byte, base64.StdEncoding.EncodedLen(len(clientProof)))
base64.StdEncoding.Encode(buf, clientProof)
return buf
}
func computeServerSignature(saltedPassword, authMessage []byte) []byte {
serverKey := computeHMAC(saltedPassword, []byte("Server Key"))
serverSignature := computeHMAC(serverKey, authMessage)
buf := make([]byte, base64.StdEncoding.EncodedLen(len(serverSignature)))
base64.StdEncoding.Encode(buf, serverSignature)
return buf
}
// Get the server certificate hash for SCRAM channel binding type
// tls-server-end-point.
func getTLSCertificateHash(conn *tls.Conn) ([]byte, error) {
state := conn.ConnectionState()
if len(state.PeerCertificates) == 0 {
return nil, errors.New("no peer certificates for channel binding")
}
cert := state.PeerCertificates[0]
// Per RFC 5929 section 4.1: If the certificate's signatureAlgorithm uses
// MD5 or SHA-1, use SHA-256. Otherwise use the hash from the signature
// algorithm.
//
// See: https://www.rfc-editor.org/rfc/rfc5929.html#section-4.1
var h hash.Hash
switch cert.SignatureAlgorithm {
case x509.MD5WithRSA, x509.SHA1WithRSA, x509.ECDSAWithSHA1:
h = sha256.New()
case x509.SHA256WithRSA, x509.SHA256WithRSAPSS, x509.ECDSAWithSHA256:
h = sha256.New()
case x509.SHA384WithRSA, x509.SHA384WithRSAPSS, x509.ECDSAWithSHA384:
h = sha512.New384()
case x509.SHA512WithRSA, x509.SHA512WithRSAPSS, x509.ECDSAWithSHA512:View on GitHub (pinned to ec1a0befd2)
Solutions
- Ensure the server presents an X.509 certificate during the TLS handshake.
- If binding is not required, set Config.ChannelBinding to "" or "disable".
- Use a normal certificate-based TLS deployment end-to-end.
Defensive patterns
Strategy: validation
Validate before calling
// Ensure the server presents a cert before relying on channel binding.
// You can preflight by dialing TLS separately, or simply avoid requiring binding
// when the deployment uses PSK/anonymous TLS.
func shouldRequireBinding(serverPresentsCert bool) string {
if serverPresentsCert {
return "require"
}
return "" // auto
} Try / catch
if err := connect(); err != nil && strings.Contains(err.Error(), "no peer certificates for channel binding") {
cc.ChannelBinding = "" // relax and retry without binding
} Prevention
- Ensure servers present X.509 certificates during TLS.
- Do not set ChannelBinding="require" with PSK or anonymous TLS.
- Use standard certificate-based TLS end-to-end.
When it happens
Trigger: A TLS connection (*tls.Conn) whose ConnectionState().PeerCertificates is empty, encountered while deriving channel binding data in scramAuth. Happens with anonymous TLS (TLS_NULL_WITH_NULL-style), TLS-PSK, or when a proxy completes TLS without forwarding a server cert.
Common situations: Internal mesh/proxy using PSK or anonymous cipher suites; misconfigured TLS termination that presents no server certificate; exotic TLS configs.
Related errors
- channel binding required but server does not support SCRAM-S
- channel binding required but channel binding data is not ava
- invalid SCRAM ServerSignature received from server
- unable to add CA to cert pool
- invalid SCRAM server-first-message received from server: did
AI-assisted analysis of jackc/pgx@ec1a0befd2 (2026-08-04).
Data as JSON: /data/errors/97a83ccf85cc32d7.json.
Report an issue: GitHub.