I am using below code to connect MySQL database in PHP.
try {
shell_exec("ssh -f -L 3307:127.0.0.1:3306 ronak#server_ip sleep 60 >> logfile");
$this->_conn = $this->dbh = new PDO('mysql:host=127.0.0.1;dbname=my_db', DB_USER, DB_PASS);
$this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Couldn't connect to database. Please try again!");
}
I want to direct connect with remote MySQL host. Server is on azure virtual machine. How can I do such a configurations?
I already opened 3306 port in azure portal for MySQL. I don't know how to use it in here without ssh tunnel.
Thanks.
1) change my.conf (whatever your mysql conf file is called). And set bind-address to 0.0.0.0 as it is prob 127.0.0.1
2) stop/restart mysql daemon
Connections now are not limited to those from localhost (what you are when you ssh). The default is localhost for obvious security reason until dev guy tweaks it
3) add database user perhaps coming in from diff ip addr
CREATE USER 'fred7'#'192.168.2.7' IDENTIFIED BY 'my_password';
4) grants
GRANT ALL PRIVILEGES ON test7db.* TO 'fred7'#'192.168.2.7';
5) firewall
For 3 and 4, let's say the mysql server is on aws ec2 and i am sitting at a public library using sqlyog or workbench. That prog will alert me if connect failure stating something like connection failed for user 'fred7'#'gfs6.nyc.comcastbusiness.net'. So it is pretty obvious how to do 3 and 4 then.
Good luck!
I have a connection.php file that is suppose to connect to a remote database.
Here is the code:
<?php
try {
$conn = new PDO('mysql:host=IP;port=PORT;dbname=DBNAME', 'USERNAME', 'PASSWORD');
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
?>
Now all my variables I believe are correct since I can connect to the database through Toad. I used this same PDO format for my own database connection through localhost and it works fine. I am not sure what the problem is. Since i can use Toad i believe that the server already allows remote access to it, but i am not sure on that. Any input would be nice.
Also this is the Error that PDOException is coming back with:
SQLSTATE[HY000] [2003] Can't connect to MySQL server on 'IP' (111)
111 means connection refused,
It probably means that your MySQL server is only listening the localhost interface.
If you have lines like this :
skip-networking
bind-address = 127.0.0.1
You should comment them In your my.cnf configuration file (add a # at the beginning of the lines), and restart MySQL.
well, in you /etc/mysql/my.cnf :
you should find out this:
skip-networking
bind-address = 127.0.0.1
You gotta comment the first one, and change the ip to 0.0.0.0 or to the ip of your remote host that you want to allow (recommended)
Also, you may don't have a user to connect to that host, i mean, mysql users are like 'root'#'192.168.1.1', so you may try to access with a user that doesn't exists. Try to create it and then grant to it all privilegies.
Just execute this couple commands on mysql:
CREATE USER 'root'#'192.168.1.100' IDENTIFIED BY '***';
GRANT ALL PRIVILEGES ON * . * TO 'root'#'192.168.1.100' IDENTIFIED BY '***';
Also, make sure that mysql is listening to in the right port, if using linux:
netstat -tlpn
should do the work, at least that's how i fixed similar problems.
I was facing the same error for a few hours now.
Turns out I had given the wrong port in my code.
My port to connect was the default port 3306 I was using 3327.
Hope it helps someone maybe.
Okay, this is something I've been banging my head on for a few weeks now, so just bear with me. When I set up my postgres database, I wanted to connect to it only through the local Unix socket. Just like how I set up my MySQL database, and subsequent PHP scripts I wrote for it. Thus, the bottom of my pg_hba.conf file looked like this:
# TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all md5
# IPv4 local connections:
#host all all 127.0.0.1/32 md5
# IPv6 local connections:
#host all all ::1/128 md5
I was, and still am, able to interface with my db via the psql command-line utility, and do anything I need to do without issue. However, when I tried to write a simple PHP script to connect to the db, it would always fail:
<?php
$dbhost = "localhost";
$dbname = "postgres";
$dbuser = "postgres";
$dbpassword = "####";
$conn_string = "host=$dbhost dbname=$dbname user=$dbuser password=$dbpassword";
$dbconn = pg_connect($conn_string);
if($dbconn)
{
echo "<p>Win!</p>";
}
else
{
echo "<p>Connect failed!</p>";
exit();
}
pg_close($dbconn);
?>
I was absolutely dumbstruck for weeks as to why PHP wouldn't establish a simple Unix socket connection, especially after writing quite a few scripts with the mysqli library for my MySQL db that used local connections! However, I finally un-commented the line associated with the loop-back address, and like magic it suddenly worked! This indicates to me that when 'localhost' is passed as the host parameter of pg_connect, it uses the loop-back interface, rather than just the local Unix socket.
It's not the end of the world, but is there a way to use PHP in a way so that it connects via a local Unix socket, or does it not support this type of connection with postgresql?
Set host in the connection string to the value of the directory that holds the unix socket.
So if the socket is at /var/run/postgresql/psql.sock then try:
pg_connect("host=/var/run/postgresql dbname=..etc...");
Other comments on the PHP docs page for pg_connect indicate that you can also leave out the host key/value completely and it will work - but I haven't tried.:
http://php.net/manual/en/function.pg-connect.php
I've got a web server with one host, and I'd like to use the database on another host.
I'd like to use port forwarding to do this, and have already set up the forwarded port using
ssh -P -fg -L23307:myserver.net:3306 myname#myserver.net sleep 1d
This seems to be working properly (although if someone could tell me how to check, that would be great), but I can't get PHP to connect to MySQL through that port - it keeps trying to connect to its own local MySQL database (which isn't running).
$mlink = mysql_connect( "localhost:23307", "myusername", "mypassword" );
mysql_select_db( 'mydatabase', $mlink ) or die ( "Error - cannot connect to database localhost:23307.<br />Error: ".mysql_error() );
As you can see, I'm not doing anything that complicated, so why does it keep trying to connect locally?
So, turns out the answer was "don't trust people when they say they've opened the port on the firewall".
Anyone want a job?
I faced the same issue. But there was no firewall problem involved. In fact, when you are doing SSH tunneling, you need not have to change any firewall setting.
I solved it by changing 'localhost' to '127.0.0.1' in the mysql_connect() parameter list.
Refernce link - https://blog.rjmetrics.com/2009/01/06/php-mysql-and-ssh-tunneling-port-forwarding/
Excerpt -
Connecting via MySQL
It’s time to see all of our hard work pay off. From our local machine, we simply issue the following command:
$mysql -u sqluser -p -h 127.0.0.1 -P 3307
Notice that the MySQL host is 127.0.0.1, which is the same as the bind-address value on the remote server’s my.cnf file. It’s important that we use this value and not localhost, since we are ultimately accessing a forwarded TCP port, and specifying localhost causes MySQL to ignore TCP altogether and simply connect to the local server via a local socket. Accordingly, notice that we have specified port 3307 to make the connection; this is the TCP port we are forwarding.
I have my database on remote Linux machine, and I want to connect using SSH and PHP functions (I am currently using ssh2 library for that). I tried using mysql_connect, but it gives me can't access (although I have granted permission)
when I tried using this function:
$connection = ssh2_connect('SERVER IP', 22);
ssh2_auth_password($connection, 'username', 'password');
$tunnel = ssh2_tunnel($connection, 'DESTINATION IP', 3307);
$db = mysqli_connect('127.0.0.1', 'DB_USERNAME', 'DB_PASSWORD',
'dbname', 3307, $tunnel)
or die ('Fail: '.mysql_error());
I got error "mysqli_connect() expects parameter 6 to be string, resource given". How can I resolve this?
SSH Tunnel Solution
Set up an SSH tunnel to your MySQL database server (through a Jumpbox proxy for security).
(A) GUI Tools
Depending on your requirements, you can use a GUI MySQL client with SSH Tunnelling support built-in such as Visual Studio Code Forwarding a port / creating SSH tunnel, TablePlus or use PuTTY to setup local port forwarding.
On macOS, I like Secure Pipes or TablePlus.
(B) Command Line
Step 1.
ssh -fNg -L 3307:10.3.1.55:3306 username#ssh-jumpbox.com
The key here is the '-L' switch which tells ssh we're requesting local port forwarding.
I've chosen to use port 3307 above. All traffic on my local machine directed to this port will now be 'port-forwarded' via my ssh client to the ssh server running on the host at address ssh-jumpbox.com.
The Jumpbox ssh proxy server will decrypt the traffic and establish a network connection to your MySQL database server on your behalf, 10.3.1.55:3306, in this case. The MySQL database server sees the connection coming in from your Jumpbox' internal network address.
Local Port Forwarding Syntax
The syntax is a little tricky but can be seen as:
<local_workstation_port>:<database_server_addr_remote_end_of_tunnel>:<database_server_port_remote_end> username#ssh_proxy_host.com
If you're interested in the other switches, they are:
-f (go to background)
-N (do not execute a remote command)
-g (allow remote hosts to connect to local forwarded ports)
Private Key Authentication, add (-i) switch to above:
-i /path/to/private-key
Step 2.
Tell your local MySQL client to connect through your SSH tunnel via the local port 3307 on your machine (-h 127.0.0.1) which now forwards all traffic sent to it through the SSH tunnel you established in step 1.
mysql -h 127.0.0.1 -P 3307 -u dbuser -p passphrase
Data exchange between client and server is now sent over the encrypted SSH connection and is secure.
Security note
Don’t tunnel directly to your database server. Having a database server directly accessible from the internet is a huge security liability. Make the tunnel target address the internet address of your Jumpbox/Bastion Host (see example in step 1) and your database target the internal IP address of your database server on the remote network. SSH will do the rest.
Step 3.
Now connect up your PHP application with:
<?php
$smysql = mysql_connect( "127.0.0.1:3307", "dbuser", "passphrase" );
mysql_select_db( "db", $smysql );
?>
Credit to Chris Snyder's great article detailing ssh command line tunnelling for MySQL connectivity.
Unfortunately, the ssh2 tunnel offered by php doesn't seem able to handle a remote mysql connection as you cannot specify the local port to tunnel (it only works with port 22 or whatever ssh port your remote server is running on). My solution to this is to just open the tunnel via exec() operator and connect as usual from there:
exec('ssh -f -L 3307:127.0.0.1:3306 user#example.com sleep 10 > /dev/null');
$mysqli = new mysqli('127.0.0.1', 'user', 'password', 'database', '3307');
I was looking for the same thing, but I prefer not to need external commands and manage external processes. So at some point I thought, how hard can it be to write a pure PHP MySQL client which can operate on any PHP stream? It took me about half a day, based on the MySQL protocol documentation.
https://gist.github.com/UCIS/4e509915ed221660e58f5169267da004
You can use this with the SSH2 library or any other stream:
$ssh = ssh2_connect('ssh.host.com');
ssh2_auth_password($ssh, 'username', 'password');
$stream = ssh2_tunnel($ssh, 'localhost', 3306);
$link = new MysqlStreamDriver($stream, 'SQLusername', 'SQLpassword', 'database');
$link->query('SELECT * FROM ...')->fetch_assoc();
It does not implement the complete mysqli API, but it should work with all plain-text queries. Please be careful if you decide to use this, I haven't thoroughly tested the code yet and the string escaping code has not been reviewed.
According to the docs, that last parameter is supposed to be a socket or pipe name, something like '/var/run/mysql/mysql.sock'. Since you're not connecting using a UNIX socket, that doesn't apply to you... so try just leaving it out.
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 yourdbuser#127.0.0.1 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 sshuser#remotehost.com
-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 hostkeys-00#openssh.com 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.
even i tried it by doing ssh both by root credentials and and public private key pair, but it allows me to conect through command line but not through php code. I tried by creating tunnel also(by using ssh2 functions),ans running shell commands from php code(system,exec etc), nothing worked. Finally i tried ssh2 function to execute shell command and it finally worked :) Here is code, if it helps you:----
$connection = ssh2_connect($remotehost, '22');
if (ssh2_auth_password($connection, $user,$pass)) {
echo "Authentication Successful!\n";
} else {
die('Authentication Failed...');
}
$stream=ssh2_exec($connection,'echo "select * from zingaya.users where id=\"1606\";" | mysql');
stream_set_blocking($stream, true);
while($line = fgets($stream)) {
flush();
echo $line."\n";
}
it worked for me try this if want to use php functions specifically.
Make sure that your username and password that you are connecting with has the right hostname permissions. I believe you can use '%' for a wildcard. Also if you are connecting to remote machine (which I would assume you are if you are trying to ssh into it) that is not on your local network you will have to forward the ports on your router where the server is for outside traffic to be able to connect to it.
http://www.lanexa.net/2011/08/create-a-mysql-database-username-password-and-permissions-from-the-command-line/
When using ssh2 to connect, since there is no special function for php to use ssh2 to connect to mysql, we can only use the traditional socket and mysql protocol for data interaction.
When we use the ssh2_tunnel method, if the creation is successful, a socket object will be returned, then we can use this socket object for mysql data interaction. Of course, we need to understand the mysql protocol, which is the so-called "handshake packet"
......
$tunnel = ssh2_tunnel(....)
......
//we need to construct the mysql data packet and then use fwrite to transfer this packet to mysql host
fwrite($tunnel, MYSQLDATAPACKET)
when we use ssh2_connect method to connect the mysql host, it will return a MySQL handshake packet, it looks like this:
a 5.5.5-10.3.34-MariaDB-cll-lve�WfyP`uKW����RtscuF:/}J7umysql_native_password!��
here is the mysql handshake packet structure:
size(byte) description
1 protocol version
n server version
4 connection id
8 auth-plugin-data-part-1
1 filler
2 capability flags
1 character set
2 status flags
2 capability flags
1 length of auth-plugin-data
10 reserved
13 auth-plugin-data-part-2
n auth-plugin name
so we should parse the byte array by using such structure.
After receving the Mysql handshake, which means we have connected the mysql host, and now we need to login mysql, so we need to construct the mysql send data packet
here is the data structure: (HandshakeResponse41)
4 capability flags, CLIENT_PROTOCOL_41 always set
4 max-packet size
1 character set
string[23] reserved (all [0])
string[NUL] username
if capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA {
lenenc-int length of auth-response
string[n] auth-response
} else if capabilities & CLIENT_SECURE_CONNECTION {
1 length of auth-response
string[n] auth-response
} else {
string[NUL] auth-response
}
if capabilities & CLIENT_CONNECT_WITH_DB {
string[NUL] database
}
if capabilities & CLIENT_PLUGIN_AUTH {
string[NUL] auth plugin name
}
if capabilities & CLIENT_CONNECT_ATTRS {
lenenc-int length of all key-values
lenenc-str key
lenenc-str value
if-more data in 'length of all key-values', more keys and value pairs
}
See Also: https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse41
Okay, so we have connected the mysql host successfully, and then you can query the database.
Here is the sample code for the Mysql Handshake and Mysql Socket Login:
function parseMysqlHandshakePack($hex_string)
{
$dataField = {
"protocol_version" => "",
"server_version" => "",
"thread_id" => "",
"salt1" => "",
"salt2" => "",
"salt" => "",
}
$dataField["protocol_version"] = UtiliHelper::HexToInt(UtiliHelper::HexSub($hex_string,0,1));
$dataField["server_version"] = UtiliHelper::HexToStr(UtiliHelper::HexSub($hex_string,1,7));
$dataField["thread_id"] = UtiliHelper::HexToInt(UtiliHelper::HexSub($hex_string,8,4));
$dataField["salt1"] = UtiliHelper::HexSub($hex_string,12,8);
$dataField["salt2"] = UtiliHelper::HexSub($hex_string,39,12);
$dataField["salt"] = $dataField["salt1"] . $dataField["salt2"];
return $dataField;
}
function constructMysqlLoginPacket($username, $password, $database, $salt){
$tags = [
"power_tag" => "",
"power_ext" => "",
"max_length" => "",
"charset" => "",
"fill_pad" => "",
"username" => "",
"password" => "",
"database" => "",
"client_auth_plugin" => "",
"payload" => ""
];
$tags['power_tag'] = "8da2";
$tags['power_ext'] = "0b00";
$tags['max_length'] = "000000c0";
$tags['charset'] = "08";
$tags['fill_pad'] = "0000000000000000000000000000000000000000000000";
$tags['client_auth_plugin'] = "6d7973716c5f6e61746976655f70617373776f726400";
$tags["payload"] = "150c5f636c69656e745f6e616d65076d7973716c6e64";
$tags['username'] = UtiliHelper::StrToHex($username)."0014";
$tags['password'] = UtiliHelper::encryptionPass($password,$salt);
$tags['database'] = UtiliHelper::StrToHex($database)."00";
$message = "";
foreach ($tags as $tagv){
$message .= $tagv;
}
return UtiliHelper::IntToHex(strlen($message)/2)."01".$message;
}
the $salt parameter came from the Handshake phase, so you need to parse the mysql handshake message and get the salt.
The UtiliHelper is a custom class which is from a 3rd party party project in Github: https://github.com/gphper/PHPMysql/blob/master/src/UtiliHelper.php