If you work with real infrastructure for more than a month, every database you care about ends up behind a bastion host, because nobody with their name on the firewall rules exposes 5432 to the internet, and yet the default workflow for reaching that database from a desktop GUI is still a ritual from 2005: open a terminal, type an ssh -L incantation you half-remember, leave the terminal open forever, point your database client at localhost:15432, and hope nobody reboots the jump box mid-join.
The incantation itself is fine; ssh -L 15432:db.internal:5432 ops@bastion.example.com is honest, well-documented plumbing, and every engineer should know what it does, which is to bind a local port that travels through the SSH session and pops out on the far side aimed at the database. The problem is everything around it: the local port number is a fiction you have to remember, the session dies silently and your client starts hanging on a dead socket, the tunnel and the connection profile live in two different tools that know nothing about each other, and the day you add a second environment you now have a spreadsheet of port numbers in your head, 15432 for staging, 15433 for prod, 15434 for the analytics replica somebody added in March.
Jump hosts make it worse in the specific way that matters, because regulated or grown-up networks rarely let the bastion see the database directly, so the real path is laptop to bastion to internal relay to database, and now the one-liner is a ProxyJump chain with per-hop credentials, and the number of people on the team who can reproduce it from memory is one, and that person is on vacation.
What the tunnel manager pattern looks like
The fix is not a better cheatsheet; it is treating the tunnel as a first-class object with a name, a target, credentials, and a lifecycle, the same way the database connection itself is a first-class object. In Mongrel that is literally the model: an SSH profile holds the host, the port, the key or agent identity, and any jump-host chain, a tunnel profile references it and declares the local and remote endpoints, and a database connection says “use this tunnel” the way it says “use this database name,” so the bastion stops being a terminal window you babysit and becomes a dropdown in the connection dialog.
The part that sells it in daily use is the lifecycle, because the app that opens the tunnel also owns reconnecting it, so when the session drops, the tunnel comes back with the same local endpoint and the query you were running retries against a live socket instead of a corpse, and when you close the connection the tunnel closes with it instead of lingering in a forgotten terminal for three weeks holding a port hostage.
For the common case the whole thing compresses to one mental step:
Connection: analytics-prod
Host: db.internal:5432 (never touches your laptop directly)
Via: tunnel "prod-bastion" (ops@bastion.example.com, ProxyJump relay)
Local: auto-assigned, shown, forgettable
Compare that to the cheatsheet version, where the same setup is ssh -J ops@bastion.example.com ops@relay.internal -L 15433:db.internal:5432 -N -f plus a note in your head that 15433 means prod, and the GUI pointed at localhost with no idea why, and you can see why teams that adopt tunnel profiles stop documenting the manual path at all; the profile is the documentation, and it executes.
The honest tradeoff
The CLI is not wrong, and for a one-off inspection on a box you will never touch again, ssh -L typed from memory is faster than opening any GUI, full stop, and I still do it. The GUI pattern wins when the connection is a relationship rather than an encounter: the staging database you check every morning, the production replica you only open during incidents at 2 a.m., which is precisely the moment you do not want to be reconstructing a ProxyJump chain from a wiki page, and the customer database whose bastion requires the key with the passphrase you are allowed to use exactly twice a year.
There is also a security note worth saying plainly, because tunnel managers concentrate credentials, and the answer is the boring correct one: keep keys in the agent or the system keyring, reference identities rather than pasting private keys into profiles, and let the tool request the agent rather than store secrets, which is what Mongrel does, so the profile holds pointers and policy, not key material.
Where this lands
A database client and an SSH tunnel manager turn out to be two halves of one tool, since nearly every non-toy database connection wants the second to reach the first, and keeping them in separate apps means every connection is really two connections you maintain by hand. Mongrel puts them in the same window, next to the Kubernetes view and the Docker view and the API client, because the database behind the bastion is usually next to all of those too, and the 7-day trial is the easiest way to point it at your own bastion and see whether the dropdown beats the cheatsheet; download it at visorcraft.com/download and the tunnel profiles are under the same connection dialog you would expect, no separate plugin, no CLI fallback required.
