I believe that the reason I (and I suppose most people) have a problem getting this to work is because the user in the mysql server is set to only allow from "localhost" and not 127.0.0.1, the IP address of localhost.
I got this to work by doing the following steps:
Step 1: Allow 127.0.0.1 host for target user
SSH normally into your server, and log in with the mysql root user, then issue the command:
GRANT ALL ON yourdbname.* TO [email protected] IDENTIFIED BY 'yourdbpassword';
The key of course, is specifying 127.0.0.1 above.
Step 2: Start local SSH tunnel to MySQL
You can now start your local SSH tunnel to the remote MySQL server, like so:
ssh -vNg -L 33306:127.0.0.1:3306 [email protected]
-v
makes ssh operate in verbose mode, which kind of helps to see what's happening. For example, you'll see debugging output like this in your terminal console when you attempt a connection:
debug1: client_input_global_request: rtype [email protected] want_reply 0
debug1: Connection to port 33306 forwarding to 127.0.0.1 port 3306 requested.
and output like this when you close the connection:
debug2: channel 2: is dead
debug2: channel 2: garbage collecting
debug1: channel 2: free: direct-tcpip: listening port 33306 for 127.0.0.1 port 3306, connect from 127.0.0.1 port 52112 to 127.0.0.1 port 33306, nchannels 3
-N
makes ssh issue no commands, and just wait instead after establishing connection.
-g
allows remote hosts to connect to local forwarded ports. Not completely sure if this is necessary but it might be useful for multiplexing multiple connections through the same SSH tunnel.
-L
This is the main parameter that specifies the local port 33306
to connect to the remote host's local IP address 127.0.0.1
and the remote host's mysql port, usually 3306
.
You can use whatever mechanisms / other parameters needed after this to connect through SSH to your remote host. In my case, I use key files configured in my ~/.ssh/config
so I just need to specify user@host
to get in.
Issuing the command like this runs SSH in the foreground, so I can easily close it with Ctrl + C
. If you want to run this tunnel in a background process you can add -f
to do this.
Step 3: Connect from PHP / other mysql compatible methods
The SSH tunnel running from above on your localhost will behave exactly like as if your mysql was running on 127.0.0.1
. I use port 33306
(note the triple 3) which lets me run my local sql server at its normal port. You can now connect as you would normally do. The mysql
command on the terminal looks like this:
mysql -h 127.0.0.1 -P 33306 -u yourmysqluser -p
where -P
(capital P) specifies the port where your SSH tunnel's local end is accepting connections. It's important to use the 127.0.0.1
IP address instead of localhost
because the mysql cli will try to possibly use the linux socket to connect.
For PHP connection strings, my data source name string (for my Yii2 config) looks like this:
'dsn' => 'mysql:host=127.0.0.1;dbname=yourdbname;port=33306',
Passwords, and usernames are specified as normal.