SSH · Security · MySQL

MySQL GUI with SSH Tunnel: Connect Securely to Remote Databases

pimvdmolen.nl · · ~9 min read

A MySQL GUI with SSH tunnel support is the difference between a safe remote workflow and a database port exposed to the world. If your staging or production MySQL lives on a private network, your desktop client should reach it through SSH — not through a wide-open firewall rule.

What an SSH tunnel does

Instead of:

your Mac → public :3306 → MySQL

you do:

your Mac → SSH (port 22) → bastion/jump host → private MySQL:3306

The GUI opens the SSH session, forwards a local port (or an internal channel), and speaks MySQL through that encrypted path. From the database’s point of view, the connection often appears to come from the bastion.

When you need it

Use SSH tunneling when:

  • MySQL listens on a private IP only
  • a jump host / bastion is the approved entry point
  • your hosting provider blocks direct 3306 from the internet
  • you are on untrusted networks (cafés, airports) and still need staging access

Skip tunnels only when you are already on a VPN that makes the DB reachable privately — and even then, least-privilege users still matter.

What the GUI needs from you

Typical SSH tunnel fields:

Field Example Notes
SSH host bastion.example.com The jump server
SSH port 22 Sometimes non-standard
SSH user deploy OS user, not MySQL user
Auth private key / password Keys preferred
MySQL host 10.0.1.40 or mysql.internal As seen from the bastion
MySQL port 3306 Private port
MySQL user/password app_ro / secret Database credentials

The most common mental error: putting the public website hostname in the MySQL host field while also enabling SSH. After SSH is enabled, the MySQL host should usually be the internal hostname/IP.

Key-based auth tips (macOS / Linux)

ssh-add --apple-use-keychain ~/.ssh/id_ed25519
ssh -i ~/.ssh/id_ed25519 [email protected]

If Terminal SSH works and the GUI does not, compare:

  • exact key path
  • passphrase prompting
  • whether the key is loaded in the agent
  • SSH port and username typos

On Windows, keep track of OpenSSH key paths vs PuTTY .ppk formats — some clients accept one and not the other.

Security practices that actually matter

  1. Disable direct public 3306 once tunnels work
  2. Use a dedicated SSH user with limited rights on the bastion
  3. Prefer read-only MySQL users for exploration
  4. Do not reuse production passwords in local Docker
  5. Turn off tunnels when done on shared machines
  6. Log and rotate access for team bastions

An SSH tunnel is not a free pass to run DELETE FROM users without a where clause.

Troubleshooting checklist

SSH succeeds, MySQL fails

  • MySQL host/IP is wrong from bastion’s perspective
  • security group allows bastion → DB but you used a public IP
  • MySQL user is not allowed from the bastion host (user@bastion-ip)

SSH fails immediately

  • key permissions (chmod 600)
  • wrong user
  • bastion allowlist does not include your current IP
  • corporate network blocking outbound 22

Works in CLI SSH tunnel, fails in GUI

Recreate the same mapping manually to compare:

ssh -N -L 3307:10.0.1.40:3306 [email protected]

Then point the GUI at 127.0.0.1:3307 temporarily. If that works, the GUI’s tunnel settings need alignment.

Why this belongs in a desktop client

Browser-based admin tools on the server can bypass your laptop tunnel story — and also expand risk if the web admin is exposed. A local GUI with first-class SSH support keeps credentials and sessions on your machine while still respecting private networking.

TabulaSQL includes SSH tunneling for exactly this workflow: connect to MySQL/MariaDB behind a bastion without publishing the database port.

Related

Frequently asked questions

The GUI opens an SSH session to a bastion/jump host, then forwards MySQL traffic through that encrypted channel so the database port never needs to be public.

Almost always yes for remote environments. Exposing MySQL directly to the internet is a common cause of brute-force attacks and accidental data exposure.

You typically need SSH credentials (key preferred) for the bastion, plus separate MySQL username/password for the database itself.