Replit database connection errors in production: how to fix them
Short answer
- Read the exact error first: "not set", "endpoint has been disabled", "SSL", "too many connections" and "relation does not exist" have different fixes.
- A paused database is unpaused from the Database pane, for Development and Production. A conflicting DATABASE_URL secret can hide that button.
- Use one shared connection pool per process, and run migrations against production before you publish.
The published app loads, then every page that touches data fails. Or publishing itself stops with DATABASE_URL environment variable is not set. Database errors in production look alike from the outside, but the message in the logs tells you which of five problems you have. Here is each one with its fix.
Symptoms
DATABASE_URL environment variable is not setat publish or startup.The endpoint has been disabledor a frozen database.connection requires SSL,self-signed certificateorECONNREFUSED.remaining connection slots are reserved,too many connectionsorconnection pool exhaustedunder load.relation "users" does not existonly in production.
Likely causes
- The deployment has no
DATABASE_URL, or it points to the development database. - The database compute endpoint was paused (Replit's help center names an unpaid invoice or a transient pause during publishing).
- An external Postgres (Neon, Supabase and others) requires SSL and the connection string or client does not use it.
- The code opens a new connection or pool per request instead of sharing one.
- Tables were created in development but migrations never ran on production.
Step-by-step fix
1. Copy the exact error
Open the deployment logs and copy the first database error with its stack trace. Match it to the steps below instead of trying every fix at once.
2. "Not set": check DATABASE_URL
In the Database pane, confirm a production database exists. Then check the deployment secrets: the published app must get the production connection string. If you also defined your own DATABASE_URL secret, compare it with the value in the Database pane. A stale one overrides the right one.
3. "Endpoint disabled": unpause
Replit's help center gives the steps: open the Database pane, select Development and click Unpause database if shown, then switch to Production and do the same. If the button is missing, a conflicting DATABASE_URL secret is the usual reason. Fix or remove it, refresh and check again. Pay any open invoice so it does not recur.
4. SSL errors: enable SSL for external Postgres
Hosted Postgres providers usually require encrypted connections. Use the connection string they give you (often with sslmode=require) and do not turn certificate checks off globally to make an error disappear.
5. Pool errors: share one pool
Create the pool once when the server starts and import it everywhere. Close any client you check out manually.
// db.ts: created once per process
import { Pool } from "pg";
export const pool = new Pool({ connectionString: process.env.DATABASE_URL, max: 10 });
// in a route: use the shared pool, never `new Pool()` here
const { rows } = await pool.query("select * from orders where user_id = $1", [userId]);
6. "Relation does not exist": run migrations on production
Apply your schema to the production database before or during publish, for example by running drizzle-kit migrate in the build step. See database migrations in production.
Copy-paste prompt for Replit Agent
Open a new Agent chat (a fresh chat keeps old attempts out of its context) and paste this:
My published Replit app fails to connect to the database. Here is the exact error from the deployment logs:
[paste error and stack trace]
Please:
1. Tell me which case it is: missing DATABASE_URL, paused endpoint, SSL, connection pool, or missing tables.
2. Make sure the app creates a single shared database pool per process and never opens a pool per request.
3. Make the app fail at startup with a clear message if DATABASE_URL is missing (log only whether it is present, never the value).
4. If tables are missing in production, set up a migration command that runs against the production database during publish, and show me the SQL before it runs.
Do not delete or reset any data.How to verify the fix
- Deployment logs show a successful database connection at startup and no errors during a full user journey.
- The Production view of the Database pane shows the expected tables and new rows created from the live app.
- A quick load test (a few dozen parallel requests) does not produce pool or connection-limit errors.
For how Replit separates development and production data, read Replit dev vs production database.
FAQ
Why does my Replit app say DATABASE_URL is not set only after publishing?
The published app reads the deployment's environment, not your workspace. Check that a production database exists and that the deployment gets its connection string, without a stale DATABASE_URL secret overriding it.
What does "endpoint has been disabled" mean on Replit?
Replit's help center explains that the database compute endpoint was paused. Unpause it from the Database pane for Development and Production; if the button is missing, check for a conflicting DATABASE_URL secret.
How many database connections should my app use?
Use one shared pool per process with a modest maximum. Opening a new connection per request is the most common cause of pool exhausted errors.