Guides / FATAL: no pg_hba.conf entry ... no encryption (Postgres SSL required)
FATAL: no pg_hba.conf entry ... no encryption (Postgres SSL required)
Your managed Postgres (RDS, Heroku Postgres, Azure, Neon and others) refuses the connection with FATAL: no pg_hba.conf entry for host "203.0.113.5", user "app", database "app", no encryption. The database requires an encrypted connection, and Django connected without one. Set sslmode in your database options.
django.db.utils.OperationalError: connection to server at "db.example.com" (203.0.113.9), port 5432 failed:
FATAL: no pg_hba.conf entry for host "203.0.113.5", user "app", database "app", no encryption
What it means
The server's access rules (pg_hba.conf) only accept hostssl connections from your address, and your client tried a plain one. Related messages mean the opposite or a trust problem: server does not support SSL, but SSL was required (you asked for SSL, the server has none, typical for a local Postgres) and SSL error: certificate verify failed (you asked to verify, and it can't).
Why it happens
- Managed Postgres requires SSL, but
DATABASEShas no SSL option. Local Postgres didn't need one, so it worked in development. - Your
DATABASE_URLlacks?sslmode=require, and the library doesn't add it. - You require a certificate check (
verify-full) without giving the client the provider's CA certificate. - SSL is forced everywhere, including local development against a Postgres without SSL.
The fix
In DATABASES, pass sslmode through OPTIONS (psycopg2 and psycopg 3 both accept it):
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": os.environ["DB_NAME"],
"USER": os.environ["DB_USER"],
"PASSWORD": os.environ["DB_PASSWORD"],
"HOST": os.environ["DB_HOST"],
"PORT": os.environ.get("DB_PORT", "5432"),
"OPTIONS": {"sslmode": os.environ.get("DB_SSLMODE", "require")},
}
}
If you use a connection URL, add it to the URL, or use dj-database-url's helper:
export DATABASE_URL="postgres://USER:PASSWORD@db.example.com:5432/NAME?sslmode=require"
DATABASES = {"default": dj_database_url.config(env="DATABASE_URL", ssl_require=True)}
Which sslmode?
require: encrypts the connection and doesn't check who answered. Fine to get unblocked.verify-full: encrypts and verifies the certificate and host name. Use it in production. Download the provider's CA bundle (for RDS, the regional or global bundle from AWS) and point to it:
"OPTIONS": {"sslmode": "verify-full", "sslrootcert": "/app/certs/global-bundle.pem"},
For local development against a Postgres without SSL, use DB_SSLMODE=prefer (or disable) in your .env, which is why the example reads it from the environment.
Making it stick in production
- Bake the CA bundle into your image or fetch it at build time, and pin its path in settings.
- Test the exact connection string with
psql "$DATABASE_URL" -c "select 1"from the machine that runs the app. - Check what the connection uses:
select ssl, version from pg_stat_ssl where pid = pg_backend_pid(); - If it still refuses, the problem may be the network and not SSL: connection refused.
Or skip it
With Django Cloud you add a managed Postgres database from the dashboard and your app is connected to it, so there is no database host or port to wire up yourself.
pip install djangocloud-cli
djangocloud deploy
Free plans are available for students, AWS Activate startups, open-source, non-profit and research projects. See how Django Cloud compares with other ways to host Django.
Django is a registered trademark of the Django Software Foundation. Django Cloud is not affiliated with or endorsed by it. Found a mistake in this guide? Tell us and we will fix it.