SSH Port Forwarding to Connect to Remote MySQL Server Through Proxy: A Complete Guide


6 views

When dealing with restricted MySQL servers, SSH tunneling becomes an essential technique. In our scenario:

  • Local machine [A]: Windows workstation
  • Proxy server [B]: CentOS machine (IP 123.123.123.1) running MySQL
  • Remote MySQL [C]: Database server only accepting connections from [B]'s IP on port 3306

The most reliable method is creating an SSH tunnel from your local machine through the proxy:

ssh -L 33306:123.123.123.1:3306 user@proxy-server -N

Breakdown of parameters:

- -L 33306:123.123.123.1:3306 creates local port 33306 forwarding to remote MySQL

- user@proxy-server your credentials for the CentOS proxy

- -N prevents remote command execution (just tunnel)

After establishing the tunnel, test connectivity from your local machine:

mysql -h 127.0.0.1 -P 33306 -u remote_user -p

For production environments, consider these enhancements:

autossh -M 0 -f -N -L 33306:123.123.123.1:3306 user@proxy-server \
-o "ServerAliveInterval 30" -o "ServerAliveCountMax 3"

Some MySQL clients support SSH tunneling directly. For MySQL Workbench:

  1. Create new connection
  2. Under SSH tab:

    - SSH Hostname: proxy-server

    - SSH Username: your_proxy_user

    - MySQL Hostname: 123.123.123.1

Error: "Channel open failure"

Verify:

- Proxy server can reach remote MySQL (test with telnet 123.123.123.1 3306)

- Remote MySQL grants proper permissions to proxy IP

- SELinux/firewall rules allow forwarding




Here's the typical scenario we're addressing:

Local Machine (Windows) [A] → Proxy Server (CentOS) [B] → Remote MySQL Server [C]

Key constraints:

  • Remote MySQL [C] only allows TCP connections from Proxy [B]'s IP (123.123.123.1)
  • Proxy [B] has its own MySQL service running on default port 3306
  • You need to access [C] from local machine [A]

The most reliable method is creating an SSH tunnel through your proxy server:

# On Local Machine [A] using Windows Command Prompt:
ssh -N -L 3307:123.123.123.1:3306 username@proxy-server-ip -p 22

Explanation of parameters:

-N : Do not execute remote command
-L : Local port forwarding (bind localport:remotehost:remoteport)
3307 : Local port to use (avoid conflict with local MySQL)
123.123.123.1:3306 : Target MySQL server and port
username@proxy-server-ip : Proxy server credentials

Once tunnel is established, connect using any MySQL client:

mysql -h 127.0.0.1 -P 3307 -u mysql_username -p

For programmatic connections (Python example):

import pymysql

connection = pymysql.connect(
    host='127.0.0.1',
    port=3307,
    user='db_user',
    password='db_password',
    database='target_db'
)

# Execute queries...

Port conflicts: If you get "Address already in use" error:

netstat -ano | findstr 3307  # Windows
ss -tulnp | grep 3307        # Linux

SSH authentication: Consider using SSH keys:

# Generate keys if needed
ssh-keygen -t rsa -b 4096

# Copy to proxy server
ssh-copy-id username@proxy-server-ip

Firewall considerations: Ensure proxy server allows SSH:

sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload

For persistent connections, create a systemd service:

# /etc/systemd/system/mysql-tunnel.service
[Unit]
Description=MySQL SSH Tunnel
After=network.target

[Service]
User=your_username
ExecStart=/usr/bin/ssh -N -L 3307:123.123.123.1:3306 username@proxy-server-ip
Restart=always
RestartSec=30

[Install]
WantedBy=multi-user.target

Then enable it:

sudo systemctl daemon-reload
sudo systemctl enable mysql-tunnel
sudo systemctl start mysql-tunnel