Get started Dashboard
Troubleshooting ·

Fix Prisma “P1001: Can't reach database server”

Explore with AI

Error: P1001: Can't reach database server at `localhost:5432`

Prisma tried to open a network connection to the host and port in your connection URL and got no usable answer: the name didn't resolve, the port refused the connection, or the connect timed out. Test the same host and port with psql or nc from the same machine, then fix whatever blocks it, most often a private hostname used outside its network or at build time, an IPv6-only database host, a paused database or a password that isn't percent-encoded.

On this page

You usually meet P1001 in one of two places. The first is a Prisma CLI command such as prisma migrate deploy, prisma migrate dev or prisma db push, often inside a CI job or a platform build. The second is your running app, where Prisma Client throws it on the first query after start-up. Either way, the host and port in the message are the ones Prisma read from your connection URL.

The message says nothing about credentials, schemas or migrations. Prisma never got that far. It tried to open a network connection to that address and failed, so the whole job is to find out why that address can’t be reached from where the command ran.

What “P1001: Can’t reach database server” means

P1001 is one of Prisma’s common connection errors. Its template lives in libs/user-facing-errors/src/common.rs in prisma-engines:

Can't reach database server at `{database_location}`

Please make sure your database server is running at `{database_location}`.

The CLI prints it with the code in front, so you see Error: P1001: Can't reach database server at `host:port` . The exact quoting depends on your Prisma version. Releases from before a May 2024 change print `host`:`port`, with two pairs of backticks. Later releases print `host:port`. The v7 error reference still shows the older form.

In the Rust engine, two kinds of failure become P1001 for PostgreSQL, MySQL and SQL Server: a connection error, and a connect timeout. That second one surprises people. A firewall that silently drops packets produces the same P1001 as a host that doesn’t exist. The related P1002 means something different: the server was reached, and then timed out.

Which Prisma version printed it

Prisma’s behaviour around this error has changed across three major versions, so check which one you run before reading logs.

Prisma ORM 6 and earlier. The Rust query engine and the schema engine open the connection. Both raise P1001 for refused connections, unresolved names and connect timeouts. The Prisma 7 connection pool docs give the version 6 default connect_timeout as 5 seconds.

Prisma ORM 7. Prisma Client now uses driver adapters by default, so the Node.js driver opens the connection. Since a July 2025 change, driver adapters can report P1001 too. The @prisma/adapter-pg error mapping on the 7.9.x branch sorts the pg driver’s socket errors like this:

  • ENOTFOUND and ECONNREFUSED become P1001, Can't reach database server at host:port.
  • ETIMEDOUT becomes P1008, Operation has timed out.
  • ECONNRESET becomes P1017, Server has closed the connection.
  • TLS certificate errors become P1011.
  • Anything else is thrown as the raw driver error.

So with Prisma 7, a refused port or a bad hostname still says P1001 at runtime. A dropped packet shows up as P1008, or as a raw pg error. The pg adapter’s connectionTimeoutMillis defaults to 0, which the docs describe as no timeout, so a blocked port can hang for a long time first. Prisma CLI commands in version 7 read the URL from datasource.url in prisma.config.ts and still print P1001.

Prisma ORM 8. Prisma’s docs now default to Prisma ORM 8. Its error reference uses dotted codes in place of P-codes. A failed connection is DRIVER.CONNECTION_FAILED, raised when the database refused the connection, rejected the credentials, or did not answer within a 20 second connect timeout. Prisma ORM 7 remains supported, with its docs under /orm/v7. The rest of this page covers P1001 on versions 6 and 7.

Testing the host and port Prisma tried

Run every check from the machine, container or CI job that failed. A check from your laptop proves nothing about a build container.

# 1. What URL is the command actually using? (prints host and port only)
node -e 'const u = new URL(process.env.DATABASE_URL); console.log(u.hostname, u.port || 5432)'

# 2. Does the name resolve, and to which address family?
dig +short A    db.example.internal
dig +short AAAA db.example.internal

# 3. Is the port open?
nc -vz db.example.internal 5432

# 4. Can a real Postgres client log in?
psql "$DATABASE_URL" -c 'select 1'

If psql works from the same place, the network path is fine, and the problem is in how Prisma gets its URL: a different environment variable, a stale .env, or the wrong value in prisma.config.ts. If psql fails too, the output points at one of the causes below.

graph TB
  A[P1001 from Prisma] --> B{Host name resolves?}
  B -->|no| C[Private or misspelt hostname]
  B -->|yes| D{nc reaches the port?}
  D -->|refused| E[Database down or wrong port]
  D -->|times out| F[Firewall, allowlist or IPv6]
  D -->|yes| G{psql logs in?}
  G -->|yes| H[Prisma reads a different URL]
  G -->|no| I[Check URL encoding]
  style A fill:#fee2e2,stroke:#fca5a5,color:#7f1d1d
  style H fill:#d1fae5,stroke:#6ee7b7,color:#065f46

Cause 1: a private hostname used outside its network

How to tell it’s yours: the host in the message is an internal name such as postgres.railway.internal, and the error appears in build logs, in CI, or on your laptop. dig returns nothing from there.

Railway gives every service an internal DNS name under railway.internal. The private networking docs say private networking is only available at runtime. The build phase has no access to it, so build scripts can’t reach other services over it, and migrations that need internal connectivity should run as part of the start command. In environments created before October 16, 2025, those names resolve to IPv6 addresses only. Newer environments get both IPv4 and IPv6.

Fix: run migrations where the private network exists, and use the public URL everywhere else.

  1. Take prisma migrate deploy out of the build command.
  2. Add it as a Railway pre-deploy command. The pre-deploy docs say these run between build and deploy, inside your private network, with your service’s variables:
    npx prisma migrate deploy
    If the command fails, it isn’t retried and the deployment doesn’t go ahead, which is what you want for a migration.
  3. Or run it at the start of the start command:
    npx prisma migrate deploy && node dist/server.js
  4. For connections from outside Railway, such as CI or your laptop, open the database’s Settings, Networking and add Public Access. The PostgreSQL docs say this creates a TCP Proxy and fills a DATABASE_PUBLIC_URL variable. Traffic through the proxy is billed as network egress.
    DATABASE_URL="$DATABASE_PUBLIC_URL" npx prisma migrate status

Cause 2: an IPv6-only database host on an IPv4 network

How to tell it’s yours: the host is db.[PROJECT-REF].supabase.co, dig AAAA returns an address, dig A returns nothing, and the machine you run from has no IPv6 route.

Supabase’s connection guide says the direct connection is IPv6 only on Free and paid plans. Paid plans with the IPv4 add-on get IPv4 only, because the add-on swaps the AAAA record for an A record. Both shared pooler modes support IPv4 on all plans.

Fix: pick the Supabase string that fits the job and the network.

  1. For Prisma Client in your app, use the transaction pooler on port 6543. It’s built for many short-lived connections, and it doesn’t support prepared statements, so add pgbouncer=true:
    DATABASE_URL="postgresql://postgres.[PROJECT-REF]:[PASSWORD]@[POOLER-HOST]:6543/postgres?pgbouncer=true"
  2. For Prisma CLI commands, Supabase recommends the direct connection. From an IPv4-only network, use the session pooler on port 5432 of the pooler host:
    DIRECT_URL="postgresql://postgres.[PROJECT-REF]:[PASSWORD]@[POOLER-HOST]:5432/postgres"
    Copy [POOLER-HOST] from the Dashboard. Supabase says it can’t be built from the region alone.
  3. In Prisma 7, point the CLI at that URL in prisma.config.ts, as the PgBouncer guide shows:
    import "dotenv/config";
    import { defineConfig, env } from "prisma/config";
    
    export default defineConfig({
      schema: "prisma/schema.prisma",
      datasource: {
        url: env("DIRECT_URL"),
      },
    });
  4. If you need the direct host over IPv4, enable the IPv4 add-on.

Cause 3: a firewall or IP allowlist dropping the connection

How to tell it’s yours: the name resolves, but nc -vz host 5432 hangs and then times out. The same command works from another network.

Managed databases often filter by source IP. Supabase’s network restrictions control which IP ranges can connect to Postgres and its pooler, and they are enforced before traffic reaches the database. Cloud security groups and corporate firewalls behave the same way. Dropped packets give you no refusal, so Prisma waits for its connect timeout and then reports P1001.

Fix:

  1. Find the egress IP of the failing machine:
    curl -s https://ifconfig.me
  2. Add that IP or range to the database’s allowlist, or run the command from a network that’s already allowed.
  3. While you debug, give slow paths more time. On Prisma 6 and earlier, add connect_timeout to the URL. The PostgreSQL connector docs list its default as 5 seconds, with 0 meaning no timeout:
    DATABASE_URL="postgresql://user:pass@db.example.com:5432/app?connect_timeout=30"
    On Prisma 7 with the pg adapter, set it on the adapter:
    const adapter = new PrismaPg({
      connectionString: process.env.DATABASE_URL,
      connectionTimeoutMillis: 30_000,
    });

A longer timeout only helps a slow path. If the firewall drops everything, a longer wait still ends in P1001.

Cause 4: the database is paused, sleeping or down

How to tell it’s yours: the connection worked before, nothing in the URL changed, and nc is refused or times out. The provider’s dashboard shows the database as paused, stopped or restarting.

Supabase pauses Free Plan projects that show low activity over a 7-day period. It sends a warning email about a week before the pause, and you can restore a paused project for up to 1 year. On Railway, a service with Serverless enabled sleeps once it stops sending outbound traffic, between 5 and 10 minutes after the last packet. The first request wakes it, and that request may fail.

Fix:

  1. On Supabase, open the Dashboard, select the organisation and the paused project, then click Resume project. Paid plans aren’t paused, so upgrade if the database must stay up.
  2. On Railway, turn Serverless off for the database service and redeploy, because the setting only applies to new containers.
  3. Self-hosted, check the server and the port it listens on:
    pg_isready -h db.example.com -p 5432
    If it can’t get an answer, check that Postgres is running and that the URL’s port matches the one the server listens on.

Cause 5: special characters in the password

How to tell it’s yours: the host in the P1001 message isn’t your database host. It looks like part of your password followed by the real host, or the port is wrong.

The connection URL docs say you must percent-encode special characters in any part of a PostgreSQL URL, passwords included. Their example turns p@$$w0rd into p%40%24%24w0rd. An unencoded @, /, : or # moves where the URL parser thinks the host begins.

Fix:

  1. Encode the password:
    node -e 'console.log(encodeURIComponent(process.argv[1]))' 'p@$$w0rd'
    p%40%24%24w0rd
  2. Put the encoded value in the URL and run the test from the start of this page again.
  3. Or rotate the password to one made of letters and digits.

Confirming Prisma can reach the database

From the same machine, container or CI step that failed:

npx prisma migrate status

It should connect and list your migrations, with no P1001. Then deploy, and search the app and deploy logs for P1001 and Can't reach database server for a while. On Prisma 7, also look for P1008 and raw ECONNREFUSED or ETIMEDOUT errors, since some failures surface under those.

Stopping P1001 from coming back

  • Keep two URLs. The app uses the pooled or private URL. Migrations and CI use the direct or public one, set in prisma.config.ts.
  • Run migrations at release time. Use a Railway pre-deploy command or your platform’s release step, never the build.
  • Set a connect timeout on purpose. On the Prisma 7 pg adapter the default is no timeout, so a blocked port hangs until the OS gives up.
  • Check the URL in CI. Fail the job if DATABASE_URL points at a .railway.internal host or contains an unencoded @ in the password.
  • Keep production off the Free Plan pause. A paused Supabase project takes every query down with it.

Spotting P1001 in Railway and Supabase logs with Polylane

Polylane reads logs from connected Railway and Supabase accounts, and on Railway it also watches deploys, so a run of P1001 errors after a release can surface as an issue with the deploy in view.

Running on Railway? See how Polylane monitors Railway in production.

Common questions.

What is the difference between P1001 and P1002?

P1001 means Prisma couldn't reach the server at all: the name didn't resolve, the connection was refused, or the connect timed out. P1002 means the server was reached but then timed out. A P1001 points at the network path or the address, while a P1002 points at a slow or overloaded database.

Does Prisma 7 still throw P1001, or a raw ECONNREFUSED?

Prisma Client 7 with @prisma/adapter-pg maps the pg driver's ENOTFOUND and ECONNREFUSED errors to P1001, with the message Can't reach database server at host:port. ETIMEDOUT becomes P1008, ECONNRESET becomes P1017 and TLS certificate errors become P1011. Any other connection error, such as pg's own connect timeout, is thrown as the raw driver error.

Why does prisma migrate deploy fail with P1001 during a Railway build?

Railway's private network, the *.railway.internal hostnames, is only available at runtime, and the build can't reach it. Move prisma migrate deploy out of the build into a pre-deploy command, which runs inside the private network, or into the start command.

Which Supabase connection string should Prisma migrations use?

Supabase recommends the direct connection for migrations, but the direct host db.[PROJECT-REF].supabase.co is IPv6 only unless you buy the IPv4 add-on. From an IPv4-only network, use the session pooler on port 5432 of the pooler host, which supports IPv4 on all plans. Keep the transaction pooler on port 6543, with pgbouncer=true, for Prisma Client.

How do I give Prisma more time to connect?

On Prisma ORM 6 and earlier, add connect_timeout to the URL, for example ?connect_timeout=30. The default is 5 seconds and 0 means no timeout. On Prisma 7 with the pg adapter, set connectionTimeoutMillis on the adapter, whose default is 0 (no timeout).

My password has an @ in it. Is that the problem?

It can be. Prisma's docs say you must percent-encode special characters in any part of a PostgreSQL URL, passwords included. p@$$w0rd becomes p%40%24%24w0rd. An unencoded @ makes the URL parser read part of the password as the host.

What replaces P1001 in Prisma ORM 8?

Prisma's docs now default to Prisma ORM 8, which uses dotted codes such as DRIVER.CONNECTION_FAILED in place of P-codes. That code covers a refused connection, rejected credentials or no answer within its 20 second connect timeout. Prisma ORM 7 stays supported, with its docs under /orm/v7 and the CLI installed as prisma@prev.

Sources

  1. user-facing-errors common.rs (prisma-engines source)
  2. Add driver adapter error mappings for P1001, P1011, P1017 (prisma-engines #5556)
  3. Fix highlighting of injected info bits in error messages (prisma-engines #4368)
  4. adapter-pg errors.ts, branch 7.9.x (Prisma source)
  5. client-engine-runtime user-facing-error.ts, branch 7.9.x (Prisma source)
  6. Error reference, Prisma ORM v7 (Prisma Docs)
  7. Error reference, Prisma ORM 8 (Prisma Docs)
  8. Connection URLs, Prisma ORM v7 (Prisma Docs)
  9. PostgreSQL, Prisma ORM v7 (Prisma Docs)
  10. Connection pool, Prisma ORM v7 (Prisma Docs)
  11. Configure Prisma Client with PgBouncer, Prisma ORM v7 (Prisma Docs)
  12. How private networking works (Railway Docs)
  13. PostgreSQL (Railway Docs)
  14. Pre-deploy command (Railway Docs)
  15. Serverless (Railway Docs)
  16. Connect to your database (Supabase Docs)
  17. IPv4 address (Supabase Docs)
  18. Network restrictions (Supabase Docs)
  19. Project pausing (Supabase Docs)
  20. Polylane documentation
  21. Polylane full content

About the author

Boris Tane

Founder of Polylane

Boris Tane is the founder of Polylane. He previously founded Baselime, observability for the future of the cloud, which Cloudflare acquired. At Cloudflare he built and led the Workers observability team.

Related

Nobody should be on-call. Polylane watches your infra, finds what broke, and writes the fix.

Get started for free