DEV Community

Cover image for Prisma Can't Connect to PostgreSQL: Fix invalid port
Mahdi BEN RHOUMA
Mahdi BEN RHOUMA

Posted on Originally published at iloveblogs.blog

Prisma Can't Connect to PostgreSQL: Fix invalid port

The misleading error — Why 'invalid port number' isn't about the port

A developer on Stack Overflow reported this exact symptom after setting up Prisma with a local PostgreSQL instance:

Error: undefined: invalid port number in "postgresql://postgres:password@localhost:5432/linker"
Enter fullscreen mode Exit fullscreen mode

The port 5432 is correct, PostgreSQL is listening, and pgAdmin confirms the server is reachable. Yet Prisma refuses to connect. The error message points at the port, but the real culprit is often a password that contains characters with special meaning in a URL — @, #, :, and others. In the Stack Overflow example, the password password is benign; the user's actual issue likely stemmed from a missing or misconfigured .env file. However, the same error message routinely appears when the password itself breaks URL parsing, and that scenario is what this article addresses. The fix is to percent-encode those characters so the connection string stays intact.

Root cause — Special characters in the password break URL parsing

Prisma reads the DATABASE_URL environment variable and parses it as a standard URL. The format is:

postgresql://user:password@host:port/database
Enter fullscreen mode Exit fullscreen mode

If the password contains a special character like @, #, :, or %, the parser sees an extra delimiter and misinterprets the host, port, or path. For example, a password p@ss turns the URL into:

postgresql://postgres:p@ss@localhost:5432/linker
Enter fullscreen mode Exit fullscreen mode

The parser splits on the first @, treating p as the password and ss@localhost:5432/linker as the host. Since ss@localhost:5432 is not a valid hostname, the error surfaces as an "invalid port number" — the parser can't extract a port from the mangled host segment. The same thing happens with # (fragment delimiter), : (port delimiter), % (escape prefix), and several other special characters.

The Prisma schema itself is not at fault; the datasource db block simply delegates to the environment variable:

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}
Enter fullscreen mode Exit fullscreen mode

The fix is to percent-encode every special character in the password so the URL parser treats them as literal values.

The fix — Percent-encode special characters in DATABASE_URL

Replace each special character in your password with its percent-encoding (also called URL encoding). The accepted answer on the Stack Overflow question provides a complete reference table. Here are the most common ones:

Character Percent-encoding
! %21
# %23
$ %24
% %25
& %26
' %27
( %28
) %29
* %2A
+ %2B
, %2C
/ %2F
: %3A
; %3B
= %3D
? %3F
@ %40
[ %5B
] %5D
space %20
" %22
- %2D
. %2E
< %3C
> %3E
\ %5C
^ %5E
_ %5F
` %60
{ %7B
` `
} %7D
~ %7E

For example, if your password is p@ss#word, the encoded version is p%40ss%23word. Your .env file then becomes:

DATABASE_URL="postgresql://postgres:p%40ss%23word@localhost:5432/linker"
Enter fullscreen mode Exit fullscreen mode

Manually replacing characters is error-prone. A safer approach is to use Node.js to encode the password programmatically. Open a terminal and run:

node -e "console.log(encodeURIComponent('p@ss#word'))"
Enter fullscreen mode Exit fullscreen mode

The output is the percent-encoded password:

p%40ss%23word
Enter fullscreen mode Exit fullscreen mode

Copy the result (without quotes) and paste it into your DATABASE_URL. This method works for any password, including those with Unicode characters like £ or 円.

After updating the .env file, restart your Prisma workflow. If you were running npx prisma studio or npx prisma migrate dev, stop it and start again so the new environment variable is picked up.

Verify — Test the connection after encoding

Run a simple Prisma command that touches the database, such as prisma db push:

npx prisma db push
Enter fullscreen mode Exit fullscreen mode

If the connection succeeds, you'll see output like:

Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "linker", schema "public" at "localhost:5432"

Your database is now in sync with your Prisma schema. Running generate... (Use --skip-generate to skip the generators)
Enter fullscreen mode Exit fullscreen mode

If you still get the same error, double-check that you encoded every special character. A common mistake is leaving the @ in the password unencoded because it looks like the host separator. Also, ensure you didn't accidentally encode the : between user and password — only the password itself needs encoding.

For a more direct test, you can use psql with the original (unencoded) password to confirm PostgreSQL accepts the credentials:

PGPASSWORD='p@ss#word' psql -h localhost -p 5432 -U postgres -d linker -c "SELECT 1;"
Enter fullscreen mode Exit fullscreen mode

If that works, Prisma will work too.

Two patterns that still trip you up

1. The password contains a % character

If your password already contains a literal %, you must encode it as %25. For example, pass%word becomes pass%25word. Failing to do this leaves a bare % that the parser interprets as the start of an escape sequence, often producing a different error or a malformed URL.

2. You're using a pooled connection string from Prisma Postgres

When you use Prisma's hosted Postgres, the official connection string format includes a ?sslmode=require query parameter. If your password contains special characters, they must still be encoded, but now the URL has additional delimiters (?, &). The same encoding rules apply: encode the password portion only, not the entire URL. For example:

# Pooled connection with encoded password
DATABASE_URL="postgres://USER:p%40ss%23word@pooled.db.prisma.io:5432/?sslmode=require"
Enter fullscreen mode Exit fullscreen mode

If you're on an M1/M2 Mac and encounter a different connectivity error (Can't reach database server at database:5432), that's a separate issue related to Docker networking — see the M1 Prisma connectivity guide for the fix.

FAQ

Why does Prisma say "invalid port number" when my port is correct?

The error is misleading. It usually means a special character in your password (like @, #, or %) is breaking the URL parser. Percent-encode those characters to fix it.

How do I percent-encode my PostgreSQL password for Prisma?

Replace each special character with its percent-encoding (e.g., @ becomes %40). You can use a Node.js one-liner: node -e "console.log(encodeURIComponent('your_password'))" to get the encoded version.

What if my password contains a % sign?

Encode it as %25. For example, pass%word becomes pass%25word. Otherwise the parser will treat the following characters as an escape sequence.

Can I just remove special characters from my password?

Yes, that's a valid workaround. If you control the PostgreSQL user, you can set a password that contains only alphanumeric characters and avoid encoding altogether. However, for managed databases where you can't change the password, encoding is the only option.

Does this affect Prisma Studio or only migrations?

It affects every Prisma command that reads DATABASE_URL, including prisma studio, prisma migrate, prisma db push, and the generated Prisma Client at runtime. The fix is the same everywhere.

Related


Originally published at https://www.iloveblogs.blog

Top comments (0)