# https://tunnels.io/use-cases/database

[Home](https://tunnels.io/) / [Use cases](https://tunnels.io/use-cases) / Local database access

Use case

# Hand a teammate a connection string to your local database.

A database is running on your machine and someone who is not on your network needs to query it. A raw TCP tunnel gives that port a public address, so their client connects with an ordinary connection string. TCP tunnels start on Professional at $4 a month.

[Get started →](https://tunnels.io/get-started) [See pricing](https://tunnels.io/pricing)

## One command, one connection string

`tunnels tcp 5432` opens a raw TCP tunnel to the port your database listens on. The client prints a public host and a port, and that pair is the whole handover.

```
$ tunnels tcp 5432
Active Tunnels:
▸ tcp://tunnels.host:41287 → 127.0.0.1:5432  [tcp]
```

The port is assigned when the tunnel opens, so read it off the client rather than hard-coding it. The connecting side pastes the ordinary URL for that database with our host and port in place of the local one.

```
postgresql://appuser:PASSWORD@tunnels.host:41287/appdb?sslmode=require
mysql://appuser:PASSWORD@tunnels.host:41287/appdb
redis://:PASSWORD@tunnels.host:41287/0
mongodb://appuser:PASSWORD@tunnels.host:41287/appdb?directConnection=true
amqp://appuser:PASSWORD@tunnels.host:41287/
```

psql, a GUI browser, an ORM datasource and redis-cli all take a host and a port, and none of them care that this one is ours.

## Why does the connection time out when the tunnel is up?

This is the failure that eats the first hour. Two things must be true: the tunnel client has to open a TCP connection to the database, and the database has to authenticate that account over the connection it receives.

If client and database share a machine, a loopback-only bind is fine, because the client dials `127.0.0.1` as any local tool would. The moment they do not, and that includes a database in a container with the client on the host, the loopback bind is the wall. `listen_addresses`, `bind-address`, `bind` and `net.bindIp`, in postgresql.conf, my.cnf, redis.conf and mongod.conf, all ship pointed at loopback.

Host-based rules catch the rest. Postgres consults pg_hba.conf, and MySQL stores the allowed host inside the account, so `'appuser'@'localhost'` is a different account from `'appuser'@'%'`. The symptom misleads because the tunnel client looks healthy either way: it has a live public port and nothing to hand traffic to.

## What does each database need?

All five are plain TCP, so the tunnel treats them identically. What differs is whether the client speaks TLS of its own, and the thing that catches people out.

| Service | Default port | Speaks its own TLS | What usually goes wrong |
| --- | --- | --- | --- |
| PostgreSQL | `5432` | Yes, requested with `sslmode` | No pg_hba.conf rule matches the new source address. |
| MySQL | `3306` | Yes, preferred when a certificate exists | The account is user@localhost, so it does not exist remotely. |
| Redis | `6379` | Optional, off by default | No password is set, and protected mode refuses non-loopback clients. |
| MongoDB | `27017` | Yes, off in most local installs | The driver finds a replica set and chases a hostname the caller cannot resolve. Add directConnection. |
| RabbitMQ | `5672` | Yes, on a listener you enable | The guest user is loopback-only, so local credentials fail remotely. |

Anything else speaking TCP behaves the same way. Anything needing UDP does not work at all.

## What are you putting on the internet?

A database port, with whatever authentication it was given locally. Local databases are configured for convenience: trust authentication, a reused password, a superuser doing ordinary work. None of that matters on loopback. All of it matters on a public port, which gets scanned within minutes.

Do not do this with production data.

A tunnel to a production database is a production database on the public internet, and no care taken over the tunnel changes that. Use a development copy, or a restored dump with the personal data stripped. If the only copy of what you are exposing is the one your customers depend on, stop and make one.

Four habits make the rest survivable: a dedicated account with the narrowest grants that do the job, a long random password from a tool, a tunnel that lives no longer than the conversation, and a copy of the data rather than the real thing. Only the last one fails safe on its own.

## Does the tunnel encrypt the database protocol?

No, and this is the part people get wrong. There are two legs. The leg from the tunnel client up to our edge runs over TLS, negotiated per connection, TLS 1.3 where both ends support it and TLS 1.2 as the floor. The leg from whoever is connecting down to the public port is raw TCP, because that is what a raw TCP tunnel is. Whatever the protocol puts on that wire is what travels.

So turn the database's own TLS on and require it from the client. Postgres uses `sslmode=require`, MySQL and MongoDB have equivalents, Redis and RabbitMQ want a second listener enabled first. Then the payload is encrypted between the two things that actually speak the protocol. Treat the tunnel as transport, not as confidentiality. The mechanics are in [how an outbound connection carries inbound traffic](https://tunnels.io/learn/what-is-a-reverse-tunnel).

## Which plan you need

Professional, at $4 a month or $40 a year. Raw TCP starts there and is not available below it: the free Basic plan and the Student plan carry HTTPS only, so neither can open a TCP tunnel. There is no version of this use case that runs on the free plan, and we would rather you read that here than discover it after signing up.

Professional gives you five concurrent tunnels, but they are split by protocol: at most **one raw TCP tunnel** and up to four HTTPS ones. One database at a time, in other words. Gold at $10 a month drops the split and gives ten tunnels of any kind. Professional also carries 128 GB of transfer a month. The number to watch on a database tunnel is a different one: concurrent TCP connections, capped at ten on Professional and fifty on Gold, uncapped on Premium. A connection pool sized at twenty will exhaust the Professional cap on its own, so size the pool deliberately or take Gold. Gold at $10 a month also raises the tunnel count to ten and transfer to 256 GB; Premium at $20 a month is unlimited tunnels and 512 GB. [Pricing](https://tunnels.io/pricing) is the authoritative copy.

## What this does not do

### No UDP, no SMTP

The engine carries HTTPS and raw TCP and rejects everything else by name, on every plan.

### No access control at our edge

No IP allowlist, no OAuth, no SSO. The `--httpauth` flag is an HTTP mechanism and does nothing for a TCP port. Your database's authentication is the gate.

### It is not hosting

The database stays on your machine. Auto-reconnect covers a network blip, not a laptop that went to sleep.

There is also no query logging and no request replay. The inspector on `127.0.0.1:4040` shows HTTP requests, not a raw TCP stream.

## How do you close the tunnel when you are done?

Stop the client. Interrupt it in its terminal and the public listener goes with it: the port is released, open connections drop, and there is nothing left to revoke.

Do it deliberately rather than eventually. The client reconnects on its own after an interruption, with exponential backoff and jitter. That is what you want during an afternoon of work and what you do not want overnight, because a tunnel you forgot about is a database port on the internet behind a password you chose in a hurry. Then drop the account you created and put the bind address back.

## Questions

### Can I connect to a local PostgreSQL database from another machine?

Yes, over a raw TCP tunnel. Run the client against port 5432 and it prints a public host and port on tunnels.host. The other side puts that pair into an ordinary connection string in place of localhost. Postgres still has to accept it, so listen_addresses and pg_hba.conf both have to allow it.

### Does a database tunnel work on the free plan?

No. The free Basic plan and the Student plan carry HTTPS only. Raw TCP starts on Professional at $4 a month, or $40 a year. Gold and Premium include TCP too.

### Why does my client time out when the tunnel says it is connected?

Almost always because the database is not reachable from where the tunnel client runs, or because a host-based rule rejects the new source address. Check the bind setting first, then the authentication rules: pg_hba.conf, the host part of a MySQL account, protected mode for Redis.

### Is the traffic encrypted?

The leg from the tunnel client to our edge runs over TLS, TLS 1.3 where both ends support it and TLS 1.2 as the floor. The public leg is raw TCP, so it carries whatever the database protocol puts on the wire. Enable the database's own TLS and require it from the client if the queries or results matter.

### Can I restrict who is allowed to connect to the port?

Not at our edge. There is no IP allowlisting and no OAuth in front of a tunnel, and the basic auth flag applies to HTTP tunnels rather than TCP ones. Anyone holding the host and port can open a connection, so the controls that matter are the database's: a dedicated account, a strong password and minimal grants.

## Related reading

[The four ways to reach a local port Tunnels, SSH forwarding, port forwarding and deploying, with the trade-offs of each.](https://tunnels.io/learn/how-to-expose-localhost) [How an outbound connection carries inbound traffic Why the tunnel opens outward, and what that means for firewalls and NAT.](https://tunnels.io/learn/what-is-a-reverse-tunnel) [Compared with Cloudflare Tunnel Two approaches to reaching a machine with no public address.](https://tunnels.io/compare/cloudflare-tunnel) [SSH into a machine with no public IP The other common TCP job, and often the safer one.](https://tunnels.io/use-cases/ssh) [Remote desktop without port forwarding RDP and VNC over the same raw TCP tunnel.](https://tunnels.io/use-cases/remote-desktop) [Everything people build with this Webhooks, device testing, home servers, preview URLs.](https://tunnels.io/use-cases)

More background in [Learn](https://tunnels.io/learn).

Open the port, share the string, close it again.

TCP tunnels start on Professional at $4 a month. Run one command against the port your database is on, then hand over a connection string that works from anywhere.

[Get started →](https://tunnels.io/get-started) [See plans and limits](https://tunnels.io/pricing)
