SSH access and direct Postgres
On Business and Enterprise, SSH into your SupaHost instance as a restricted user to run psql, read service logs and open a tunnel for direct Postgres connections from pg_dump, ORMs and GUI tools.
On the Business and Enterprise plans you can SSH into your instance as a restricted user. That gives you two things: a few admin commands (psql, service logs, status), and an SSH tunnel to Postgres so tools like psql, pg_dump, Prisma, DBeaver or TablePlus can connect directly.
Postgres on SupaHost listens only on the VM's localhost and isn't reachable from the internet on any plan. On Builder and Pro, use the Data API, Studio's SQL editor, the MCP execute_sql tool, or the exports on the Backups tab instead. See Connecting to your database.
How access is locked down
- You sign in as the user
supahost. It has no password, no root access and no Docker access. - Port 22 is open on the instance only while your plan includes SSH and at least one key is added. With no keys, the port is closed.
- With sudo, the account can run exactly four SupaHost commands and nothing else.
- Port forwarding is allowed only to Postgres, at
127.0.0.1:5432. - The account can't reach the cloud metadata server, so it can't pick up the VM's cloud credentials.
Add your SSH key
- Open Dashboard → your project → Connect → SSH & CLI.
- Paste your public key into Public key and click Add key. Only the owner can add keys.
- Wait up to a minute for the key to become active.
Supported key types: ed25519, RSA (2048 bits or more), ECDSA (256, 384 or 521), and hardware-backed sk-ed25519 and sk-ecdsa. You can add up to 20 keys per instance.
If you don't have a key yet:
ssh-keygen -t ed25519 -C "[email protected]"
cat ~/.ssh/id_ed25519.pub # paste this line into the dashboard
Connect
ssh [email protected]
Commands
Each command takes a project name. Run them with sudo.
| Command | What it does |
|---|---|
sudo supahost-psql <project> [-c "<sql>"] |
Opens psql on the project's database as the postgres role, or runs one statement. Reads SQL from stdin too |
sudo supahost-logs <project> [auth|rest|storage|functions|http] [--follow] |
Shows the last 200 lines of a service's logs; --follow keeps streaming |
sudo supahost-status |
Lists projects and containers, with disk, memory and uptime |
sudo supahost-db-url <project> |
Prints the project's database connection string |
Some examples:
# A quick count, from your laptop
ssh [email protected] \
sudo supahost-psql app-one -c "select count(*) from public.bookings"
# Run a migration file through stdin
ssh [email protected] sudo supahost-psql app-one < 20261111_add_rooms.sql
# Follow Auth logs while you test a sign-in
ssh [email protected] sudo supahost-logs app-one auth --follow
# Check every project and container on the instance
ssh [email protected] sudo supahost-status
http logs are the gateway's access logs for the project, which are useful when you want to see each request's path and status code.
Direct Postgres through a tunnel
Open a tunnel that forwards a port on your machine to Postgres on the instance:
ssh -N -L 5432:127.0.0.1:5432 [email protected]
Leave that running. In the dashboard, Connect → Database → Show connection string (owner only) gives you a URL like this:
postgresql://postgres:<password>@127.0.0.1:5432/p_app_one
Each project is its own database, named p_ plus the project name with dashes turned into underscores. The postgres role and its password are shared by the whole instance, so the same credentials reach every project's database; change only the database name at the end. Treat the password like the instance's master key. Now any Postgres tool on your machine can use it:
psql "postgresql://postgres:[email protected]:5432/p_app_one"
pg_dump -Fc -f app-one.dump \
"postgresql://postgres:[email protected]:5432/p_app_one"
If you already run Postgres locally on 5432, forward a different local port and use it in the URL:
ssh -N -L 6543:127.0.0.1:5432 [email protected]
psql "postgresql://postgres:[email protected]:6543/p_app_one"
ORMs and migration tools
Prisma, Drizzle, Flyway and the Supabase CLI's database commands all work through the tunnel, because to them it's an ordinary Postgres connection. Two things to keep in mind:
- The tunnel runs on your machine. It's for development, migrations and admin work. Your deployed app servers shouldn't depend on an SSH tunnel; they should use the Data API with supabase-js. See Prisma and Drizzle ORM.
- There's no connection pooler. The instance's Postgres allows 400 connections in total, shared by every project and by the Supabase services. Keep ORM pool sizes small. See Connections and timeouts.
Troubleshooting
- Permission denied (publickey): the key may not be active yet (allow a minute), or your SSH client is offering a different key. Try
ssh -i ~/.ssh/id_ed25519 [email protected]. - Connection refused or timed out on port 22: check the instance is on Business or Enterprise and at least one key is added.
password authentication failedthrough the tunnel: copy the connection string again from Show connection string. See FATAL: password authentication failed.