connection

connect ENETUNREACH 2600:1f1c:…:5432

What it means

ENETUNREACH ("network is unreachable") on a 2600:1f1c:… address means your client resolved the direct db.<ref>.supabase.co host to its IPv6 address but has no IPv6 route. The direct host is IPv6-only; IPv4-only CI runners, serverless functions, and Edge runtimes can't reach it. Connect through the Supavisor pooler host instead, which is IPv4-compatible.

Why it happens

connect ENETUNREACH 2600:1f1c:…:5432 is an operating-system network error (ENETUNREACH = "network is unreachable"), not a Postgres error. The client resolved a hostname to an IPv6 address in the 2600:1f1c:… block and then had no route to send packets to it.

On Supabase this is almost always the direct database host:

  • The direct host is IPv6-only. db.<project-ref>.supabase.co publishes an AAAA (IPv6) record and no public A (IPv4) record. If your client only has IPv4 connectivity, the address is unroutable and the socket fails immediately with ENETUNREACH.
  • Your runtime is IPv4-only. Many GitHub Actions/CI runners, serverless platforms (Lambda, Vercel functions), and Edge runtimes have no IPv6 route. They resolve the AAAA record, try to connect, and can't.
  • You hardcoded the direct host in a connection string. Older Supabase docs and copied .env files often use db.<ref>.supabase.co:5432. That endpoint only works from IPv6-capable networks.

The fix is not to force IPv4 on the direct host — there isn't a public one. Use the pooler.

How to fix it

First, confirm the cause. The direct host should return an IPv6 (AAAA) record and no IPv4 (A) record:

# IPv6 record exists (this is what your client tried to reach)
dig +short AAAA db.<project-ref>.supabase.co
# 2600:1f1c:...

# No public IPv4 record on the direct host
dig +short A db.<project-ref>.supabase.co
# (empty)

Now check the pooler host — it resolves to a routable IPv4 address:

dig +short A aws-0-<region>.pooler.supabase.com
# e.g. 52.x.x.x  (routable from IPv4-only runners)

Switch your connection to the Supavisor pooler. The hostname, username, and port all change:

# Before (IPv6-only, fails on IPv4-only clients)
postgresql://postgres:[password]@db.<project-ref>.supabase.co:5432/postgres

# After — transaction mode (port 6543), IPv4-compatible
postgresql://postgres.<project-ref>:[password]@aws-0-<region>.pooler.supabase.com:6543/postgres

# After — session mode (port 5432)
postgresql://postgres.<project-ref>:[password]@aws-0-<region>.pooler.supabase.com:5432/postgres

Two changes people miss:

  • The username becomes postgres.<project-ref> (tenant-qualified), not plain postgres. Getting this wrong yields password authentication failed.
  • The host and region come from your project's Database settings → Connection string → the "Session" / "Transaction" pooler tabs. Find your exact <region> there; don't guess it.

Once connected through the pooler, confirm the socket is live:

select 1;

Grab your exact values (host, port, region, tenant-qualified user) with the connection string builder.

How to prevent it

  • Default to the pooler host (aws-0-<region>.pooler.supabase.com) for anything that runs off your own machine — CI, serverless, Edge, and migrations. Reserve the direct host for IPv6-capable environments only.
  • Store the pooler connection string in your CI/CD secrets from the start, with the postgres.<project-ref> username, so no one copies the IPv6-only direct host into an IPv4-only runner.
  • Use transaction mode (6543) for short-lived migration and serverless connections; it also caps concurrent connections and helps you avoid too many connections.
  • SupaMigrate connects through the pooler by default for exactly this reason — the browser and any CI-style runner reach an IPv4-compatible endpoint instead of the IPv6-only direct host. See what a connection pooler is for the underlying mechanism.

Frequently asked questions

Why does it work on my laptop but fail in CI or a serverless function?
Your laptop usually has a working IPv6 route, so it can reach the direct db.<ref>.supabase.co host. Most CI runners, serverless platforms, and Edge runtimes are IPv4-only, so the same IPv6 address is unroutable and the socket fails with ENETUNREACH.
Is the direct host down or is my project broken?
Neither. db.<ref>.supabase.co resolves to an IPv6 address by design and is reachable from IPv6-capable networks. The failure is purely a routing problem on the client side. Switch to the pooler host to get an IPv4-compatible endpoint.
Which pooler port should I use — 6543 or 5432?
Use 6543 for transaction mode (short-lived connections, serverless, migrations) and 5432 for session mode (long-lived connections, or when you need session-level features like prepared statements and LISTEN/NOTIFY).

Related errors