| title | SSH Tunneling |
|---|---|
| description | Route database connections through an encrypted SSH tunnel to reach servers in private networks |
SSH tunneling routes your database connection through an encrypted tunnel to reach servers that aren't directly accessible from your Mac. TablePro manages the tunnel lifecycle, including keep-alive and auto-reconnect.
If you connect to multiple databases through the same SSH server, you can save your SSH configuration as a reusable profile. See [SSH Profiles](/features/ssh-profiles).flowchart LR
subgraph mac ["Your Mac"]
TablePro["TablePro<br>localhost:60000"]
end
subgraph ssh ["SSH Server"]
Jump["SSH Jump<br>Server"]
end
subgraph db ["Database Server"]
Database["MySQL<br>PostgreSQL<br>db:3306"]
end
TablePro -->|"Encrypted<br>Tunnel"| Jump -->|"Internal<br>Network"| Database
- TablePro opens an SSH connection to your jump server
- A local port (e.g., 60000) forwards through the tunnel
- All traffic between your Mac and the SSH server is encrypted
- The SSH server connects to the database on your behalf
- Database in private network
- Database accepts local connections only
- Need to encrypt database connection
- Access via bastion/jump host
Open connection form, toggle SSH Tunnel ON, enter SSH server details and auth, click Test Connection.
{/* Screenshot: Connection form with SSH section expanded */}
| Field | Description | Default |
|---|---|---|
| SSH Host | SSH server hostname or IP | - |
| SSH Port | SSH server port | 22 |
| SSH User | SSH username | - |
TablePro supports three SSH authentication methods:
Simple password authentication:| Field | Description |
|-------|-------------|
| **SSH Pass** | Your SSH password |
<Warning>
Password authentication is less secure than key-based authentication. Use SSH keys for production servers.
</Warning>
| Field | Description |
|-------|-------------|
| **Key File** | Path to your private key (e.g., `~/.ssh/id_rsa`) |
| **Passphrase** | Key passphrase (if encrypted) |
<Tip>
Click **Browse** to select your private key file. TablePro looks in `~/.ssh/` by default.
</Tip>
| Field | Description |
|-------|-------------|
| **Agent Socket** | Dropdown with `SSH_AUTH_SOCK`, `1Password`, or `Custom Path` |
- **SSH_AUTH_SOCK**: Uses the system `SSH_AUTH_SOCK` environment variable.
- **1Password**: Uses 1Password's default socket path, `~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock`.
- **Custom Path**: Shows a text field so you can enter another agent socket path.
<Tip>
1Password also documents `~/.1password/agent.sock` as an easier alias to type, but that shortcut only works if you created it yourself. TablePro's **1Password** option uses the default path in `~/Library/Group Containers/...`.
</Tip>
{/* Screenshot: SSH authentication methods */}
If your SSH server requires two-factor authentication via PAM (e.g., google-authenticator, duo_unix), TablePro can handle TOTP (Time-based One-Time Password) codes during login.
The TOTP option appears under Two-Factor Authentication when you select Password or Keyboard Interactive as your auth method.
TablePro generates the TOTP code automatically at connect time using a secret you provide. No need to open an authenticator app.| Field | Description |
|-------|-------------|
| **TOTP Secret** | Your base32-encoded secret (the same key you used when setting up your authenticator app) |
| **Algorithm** | Hash algorithm: SHA1 (default), SHA256, or SHA512 |
| **Digits** | Code length: 6 (default) or 8 |
| **Period** | Code rotation interval: 30 seconds (default) or 60 seconds |
<Tip>
The TOTP secret is the base32 string you got when first enrolling in 2FA. If you only have a QR code, most authenticator apps let you view the underlying secret.
</Tip>
No additional configuration needed. Just select this mode and TablePro will prompt you when it needs the code.
Setup steps:
- In the SSH tab of your connection settings, select Password or Keyboard Interactive as the auth method
- Under Two-Factor Authentication, choose your TOTP mode
- For Auto Generate: paste your base32-encoded TOTP secret
TOTP works with common PAM configurations including google-authenticator, duo_unix, and similar modules.
TablePro verifies SSH host keys to protect against man-in-the-middle attacks. On first connection to a server, you'll see the server's fingerprint and can choose to trust it. The key is then stored locally.
If a previously trusted server's host key changes, TablePro shows a warning. This could mean the server was reinstalled, or it could indicate a security issue. You can choose to accept the new key or abort the connection.
If you have entries in ~/.ssh/config, TablePro reads them automatically:
- TablePro reads your SSH config on launch
- Select a host from the SSH Host dropdown
- Settings are auto-filled from your config
Example SSH config entry:
# ~/.ssh/config
Host production-jump
HostName jump.example.com
User deploy
Port 22
IdentityFile ~/.ssh/production_key
This appears as "production-jump" in the SSH Host dropdown.
{/* Screenshot: SSH config hosts */}
When using SSH tunneling, the database host is relative to the SSH server:
| Field | Value | Description |
|---|---|---|
| Host | localhost or 127.0.0.1 |
Database is on the SSH server itself |
| Host | db.internal |
Database is on internal network |
| Port | 3306, 5432, etc. |
Database port (unchanged) |
The database runs on the same machine as your SSH server:
SSH Host: jump.example.com
SSH User: deploy
Database Host: localhost
Database Port: 3306
The database is on a different server, only accessible from the SSH server:
SSH Host: jump.example.com
SSH User: deploy
Database Host: db.internal.example.com
Database Port: 5432
Connecting to RDS through an EC2 bastion host:
SSH Host: bastion.example.com
SSH User: ec2-user
Key File: ~/.ssh/aws-key.pem
Database Host: mydb.abc123.us-east-1.rds.amazonaws.com
Database Port: 5432
When a database server sits behind multiple bastion hosts, TablePro can chain SSH hops using OpenSSH's -J (ProxyJump) flag. A single ssh process handles all intermediate jumps.
flowchart LR
subgraph mac ["Your Mac"]
TablePro["TablePro"]
end
subgraph hop1 ["Bastion 1"]
B1["Jump Host 1"]
end
subgraph hop2 ["Bastion 2"]
B2["Jump Host 2"]
end
subgraph db ["Database Server"]
Database["MySQL<br>PostgreSQL"]
end
TablePro -->|"Jump 1"| B1 -->|"Jump 2"| B2 -->|"Final Hop"| Database
- Open the connection form and switch to the SSH Tunnel tab
- Enable SSH and configure the final SSH server (the one that can reach the database)
- Expand the Jump Hosts section below the authentication settings
- Click Add Jump Host and fill in each intermediate bastion host in order
- Hosts are connected in sequence: first jump host is reached from your Mac, each subsequent host is reached through the previous one
Each jump host has:
| Field | Description |
|---|---|
| Host | Hostname or IP of the jump host |
| Port | SSH port (default 22) |
| Username | SSH username for this hop |
| Auth Method | Private Key or SSH Agent (password auth is not supported for jump hosts) |
| Key File | Path to private key (if using Private Key auth) |
Jump Host 1: admin@bastion1.example.com:22 (SSH Agent)
Jump Host 2: tunnel@bastion2.internal:2222 (Private Key)
SSH Server: deploy@final-ssh.internal:22
Database Host: db.internal:5432
This produces the equivalent of:
ssh -J admin@bastion1.example.com:22,tunnel@bastion2.internal:2222 deploy@final-ssh.internalTablePro reads ProxyJump directives from ~/.ssh/config. When you select a config host that has ProxyJump set, the jump hosts are auto-filled.
# ~/.ssh/config
Host production-db
HostName final-ssh.internal
User deploy
ProxyJump admin@bastion1.example.com,tunnel@bastion2.internal:2222
If you don't have SSH keys:
# Generate a new key pair
ssh-keygen -t ed25519 -C "your_email@example.com"
# Or use RSA for broader compatibility
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"Default key locations on macOS:
| Key Type | Private Key | Public Key |
|---|---|---|
| Ed25519 | ~/.ssh/id_ed25519 |
~/.ssh/id_ed25519.pub |
| RSA | ~/.ssh/id_rsa |
~/.ssh/id_rsa.pub |
| ECDSA | ~/.ssh/id_ecdsa |
~/.ssh/id_ecdsa.pub |
Copy your public key to the SSH server:
# Using ssh-copy-id
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
# Or manually
cat ~/.ssh/id_ed25519.pub | ssh user@server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"SSH keys must have correct permissions:
# Fix permissions
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_*
chmod 644 ~/.ssh/id_*.pub
chmod 644 ~/.ssh/configImport SSH tunnel connections from a URL instead of filling in each field. TablePro supports +ssh URL schemes that encode both SSH and database credentials in a single string.
For the full URL specification, see Connection URL Reference.
Format:
scheme+ssh://ssh_user@ssh_host:ssh_port/db_user:db_password@db_host/db_name?name=MyConnection&usePrivateKey=true
Supported schemes: mysql+ssh, postgresql+ssh, postgres+ssh, mariadb+ssh
Example:
mysql+ssh://root@123.123.123.123:1234/database_user:database_password@127.0.0.1/database_name?name=FlashPanel&usePrivateKey=true
This fills in:
- SSH Host:
123.123.123.123, SSH Port:1234, SSH User:root - Database Host:
127.0.0.1, Database User:database_user, Database:database_name - Connection Name:
FlashPanel, Auth Method: Private Key
Query parameters:
| Parameter | Description |
|---|---|
name |
Sets the connection name |
usePrivateKey |
Set to true to select Private Key authentication |
useSSHAgent |
Set to true to select SSH Agent authentication |
agentSocket |
Optional SSH agent socket path override (for example, ~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock) |
To import, open New Connection, click Import from URL, and paste the URL.
This format is compatible with TablePlus SSH connection URLs, so you can paste URLs directly when migrating. If you use SSH profiles, click **Test Connection** in the profile editor to verify SSH connectivity independently from the database connection. This helps isolate whether the problem is SSH or database-level.Symptoms: "Connection refused" when testing SSH tunnel
Causes and Solutions:
-
SSH server not running
# Test SSH connection directly ssh -v user@server -
Wrong port
- Verify SSH port (some servers use non-standard ports)
- Check with server administrator
-
Firewall blocking connection
- Ensure port 22 (or custom port) is open
- Check both local and server firewalls
Symptoms: "SSH authentication failed" or "Permission denied"
For Password Authentication:
- Verify username and password
- Check if password auth is enabled on server
- Try connecting via terminal:
ssh user@server
For Key Authentication:
- Verify key file path is correct
- Check key permissions (
chmod 600) - Ensure public key is in server's
authorized_keys - Verify passphrase (if key is encrypted)
- Try connecting via terminal:
ssh -i ~/.ssh/your_key user@server
"Private key file not found":
- Verify the path exists
- Use the Browse button to select the file
"Private key file is not readable":
chmod 600 ~/.ssh/your_key"Wrong passphrase":
- Re-enter the passphrase
- Test key manually:
ssh-keygen -y -f ~/.ssh/your_key
If the SSH tunnel connects but the database connection fails:
-
Verify database host is correct (relative to SSH server)
# From SSH server, test database connection ssh user@server "mysql -h localhost -u dbuser -p"
-
Check database port
- Ensure port matches the database server's actual port
-
Verify database credentials
- Username/password might be different from SSH credentials
TablePro uses keep-alive settings to maintain tunnels:
ServerAliveInterval=60: send keep-alive every 60 secondsServerAliveCountMax=3: disconnect after 3 missed responses
If tunnels still drop:
- Check network stability
- Verify server's
ClientAliveIntervalsetting - Check for idle timeout settings on firewalls
{/* Screenshot: SSH tunnel active */}
Use key-based authentication with Ed25519 or RSA 4096+ bits, protect keys with a passphrase, and never expose database ports directly to the internet. SSH Agent (1Password, Secretive, or ssh-agent) keeps private keys in a separate process — use it instead of storing passphrases.







