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:
- Create new connection
- 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