Fix PostgreSQL SSL Connection Required Error: Root Causes and Minimal Checks
Quick Answer
- The "SSL connection required" error occurs when a PostgreSQL server is configured to require SSL but the client attempts a non-SSL connection, or when SSL certificate validation fails.
- First check: verify the server's
sslsetting isoninpostgresql.conf, and confirm thepg_hba.confentry for your client useshostsslinstead ofhost. - Minimal fix: set the client connection parameter
sslmode=require(orverify-fullfor production) in your connection string or environment variablePGSSLMODE. - For cloud databases (AWS RDS, Google Cloud SQL, Azure DB), download the provider's CA certificate and use
sslmode=verify-fullwith the correctsslrootcertpath. - This guidance applies to PostgreSQL 9.6+ with SSL support compiled in; verify with
SHOW ssl;on the server.
What Problem It Solves
PostgreSQL supports SSL/TLS encryption for client-server connections to protect data in transit. When a server enforces SSL (via ssl=on in postgresql.conf and hostssl entries in pg_hba.conf), clients that attempt non-SSL connections receive a fatal error. This document provides the exact configuration steps, client code examples, and troubleshooting procedures to resolve SSL connection failures across development, testing, and production environments.
When This Error or Setup Appears
The "SSL connection required" error typically appears in these scenarios:
- Connecting to a cloud-managed PostgreSQL instance (AWS RDS, Google Cloud SQL, Azure Database for PostgreSQL) that enforces SSL by default
- Migrating from a local development database to a production database with SSL requirements
- Configuring a new PostgreSQL server with SSL enabled for the first time
- Using client libraries (psycopg2, node-postgres, JDBC, lib/pq) that default to
sslmode=preferorsslmode=disable
Root Cause Analysis
The error has three primary root causes:
-
Server-side SSL not enabled: The
sslparameter inpostgresql.confisoffor missing, or the required certificate/key files (ssl_cert_file,ssl_key_file) are not properly configured. -
pg_hba.conf mismatch: The client's connection attempt matches a
host(non-SSL) rule instead of ahostssl(SSL-required) rule. PostgreSQL evaluatespg_hba.confrecords in order and uses the first match. -
Client-side SSL mode too permissive: The client uses
sslmode=disableorsslmode=prefer(the default in many drivers) when the server requires SSL. Theprefermode tries SSL first but falls back to non-SSL, which fails if the server rejects non-SSL connections.
Minimal Working Configuration
Server-Side Setup
Edit postgresql.conf:
INIssl = on ssl_cert_file = '/etc/ssl/certs/server.crt' ssl_key_file = '/etc/ssl/private/server.key' # Optional but recommended: ssl_ca_file = '/etc/ssl/certs/ca.crt' ssl_min_protocol_version = 'TLSv1.2'
Edit pg_hba.conf to require SSL for specific clients:
# Require SSL for all remote connections
hostssl all all 0.0.0.0/0 scram-sha-256
# Allow non-SSL only on local socket (not network)
local all all scram-sha-256
Reload configuration:
BASHpg_ctl reload # or SELECT pg_reload_conf();
Client-Side Connection Strings
Python (psycopg2):
PYTHONimport psycopg2 # Development (encrypt only, no certificate validation) conn = psycopg2.connect("postgresql://user:pass@host:5432/db?sslmode=require") # Production (encrypt + validate CA + verify hostname) conn = psycopg2.connect( "postgresql://user:pass@host:5432/db?sslmode=verify-full&sslrootcert=/path/to/ca.pem" )
Node.js (node-postgres):
JAVASCRIPTconst { Client } = require('pg'); // Development const client = new Client({ connectionString: 'postgresql://user:pass@host:5432/db', ssl: { rejectUnauthorized: false } }); // Production const client = new Client({ connectionString: 'postgresql://user:pass@host:5432/db', ssl: { ca: fs.readFileSync('/path/to/ca.pem').toString(), rejectUnauthorized: true } });
Java (JDBC):
JAVA// Development String url = "jdbc:postgresql://host:5432/db?sslmode=require"; // Production String url = "jdbc:postgresql://host:5432/db?sslmode=verify-full&sslrootcert=/path/to/ca.pem";
Go (lib/pq):
GOimport "database/sql" import _ "github.com/lib/pq" // Development connStr := "postgres://user:pass@host:5432/db?sslmode=require" // Production connStr := "postgres://user:pass@host:5432/db?sslmode=verify-full&sslrootcert=/path/to/ca.pem" db, err := sql.Open("postgres", connStr)
Parameters and Environment Variables
Connection String Parameters
| Parameter | Values | Description |
|---|---|---|
sslmode | disable, allow, prefer, require, verify-ca, verify-full | SSL connection behavior. Default is prefer in most clients. |
sslrootcert | File path | Path to CA certificate for server certificate validation. Required for verify-ca and verify-full. |
sslcert | File path | Path to client certificate for mutual TLS. |
sslkey | File path | Path to client private key for mutual TLS. |
Environment Variables
| Variable | Equivalent Parameter | Description |
|---|---|---|
PGSSLMODE | sslmode | Sets the SSL mode for all libpq-based clients. |
PGSSLROOTCERT | sslrootcert | Sets the CA certificate file path. |
PGSSLCERT | sslcert | Sets the client certificate file path. |
PGSSLKEY | sslkey | Sets the client private key file path. |
Common Errors and Fixes
Error: FATAL: no pg_hba.conf entry for host "192.168.1.100", user "myuser", database "mydb", SSL off
Cause: The client matches a host (non-SSL) rule that doesn't exist, or the existing rule requires SSL but the client connects without it.
Fix: Add a hostssl entry in pg_hba.conf:
hostssl mydb myuser 192.168.1.100/32 scram-sha-256
Then reload: pg_ctl reload
Error: SSL error: certificate verify failed
Cause: The client's CA certificate (sslrootcert) does not match the CA that signed the server certificate.
Fix: Verify the certificate chain:
BASHopenssl verify -CAfile ca.crt server.crt
If using self-signed certificates, temporarily use sslmode=require for testing only.
Error: SSL error: hostname mismatch
Cause: The server certificate's Common Name (CN) or Subject Alternative Name (SAN) does not match the hostname used in the connection string.
Fix: Check the certificate:
BASHopenssl x509 -in server.crt -noout -text | grep -E 'Subject:|DNS:'
If the certificate cannot be regenerated, use sslmode=verify-ca (validates CA but not hostname).
Error: sslmode value "require" invalid when SSL support is not compiled in
Cause: The PostgreSQL client library was compiled without SSL support.
Fix: Reinstall the client library with SSL support:
BASH# Ubuntu/Debian sudo apt-get install libpq-dev # macOS brew install libpq # Python (use binary package with SSL) pip install psycopg2-binary
Production Notes and Security Checks
-
Never use
rejectUnauthorized: falseorsslmode=requirein production. These settings disable certificate validation and expose you to man-in-the-middle attacks. Always usesslmode=verify-fullwith a trusted CA certificate. -
Certificate rotation: Set up automated renewal for SSL certificates. Cloud providers typically provide updated CA bundles; download and deploy them before expiration.
-
Performance impact: SSL encryption adds CPU overhead and increases latency. For high-throughput applications, consider connection pooling to amortize the SSL handshake cost.
-
Firewall considerations: Ensure port 5432 (or your custom port) is open for SSL traffic. Some firewalls inspect or block SSL traffic; you may need to configure SSL inspection exceptions.
-
Client library compatibility: Older PostgreSQL client libraries may not support TLSv1.2+. Verify your client version supports
ssl_min_protocol_version = 'TLSv1.2'if you enforce it server-side. -
Multi-environment consistency: Use the same SSL configuration approach across development, staging, and production. In development, use self-signed certificates with
sslmode=require; in production, use CA-signed certificates withsslmode=verify-full.
FAQ
Q: How do I configure PostgreSQL SSL in an MCP server?
A: In your MCP server configuration, set the connection string's sslmode parameter to require or verify-full. For example:
JSON{ "mcpServers": { "postgres-ssl-fix": { "command": "python", "args": [ "-c", "import psycopg2; conn = psycopg2.connect('postgresql://user:pass@host:5432/db?sslmode=require'); print('SSL connection successful')" ], "env": { "PGSSLMODE": "require", "PGSSLROOTCERT": "/path/to/ca-certificate.crt" } } } }
Ensure the MCP server runtime has read permissions for the certificate file.
Q: How do I get the correct SSL certificate for cloud databases?
A: For AWS RDS, download the global-bundle.pem from the AWS documentation. For Google Cloud SQL, download the server CA certificate from the Cloud Console. For Azure Database for PostgreSQL, download the DigiCert Global Root G2 certificate. Always use the latest version and update before expiration.
Q: How can I test SSL connections in development without real certificates?
A: Generate self-signed certificates using OpenSSL:
BASH# Generate CA key and certificate openssl req -new -x509 -days 365 -nodes -text -out ca.crt -keyout ca.key -subj "/CN=MyCA" # Generate server key and certificate signed by CA openssl req -new -nodes -text -out server.csr -keyout server.key -subj "/CN=localhost" openssl x509 -req -in server.csr -days 365 -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt
Then connect with sslmode=require (encryption only) or sslmode=verify-ca with sslrootcert=ca.crt. Never use self-signed certificates in production.