264

In a nutshell

I want to run mysql in a docker container and connect to it from my host. So far, the best I have achieved is:

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

More details

I'm using the following Dockerfile:

FROM ubuntu:14.04.3
RUN apt-get update && apt-get install -y mysql-server

# Ensure we won't bind to localhost only
RUN grep -v bind-address /etc/mysql/my.cnf > temp.txt \
  && mv temp.txt /etc/mysql/my.cnf

# It doesn't seem needed since I'll use -p, but it can't hurt
EXPOSE 3306

CMD /etc/init.d/mysql start && tail -F /var/log/mysql.log

In the directory where there is this file, I can succesfully build the image and run it with:

> docker build -t my-image .
> docker run -d -p 12345:3306 my-image

When I attach to the image, it seems to work just fine:

# from the host
> docker exec -it <my_image_name> bash

#inside of the container now
$ mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
[...]

However I don't have that much success from the host:

> mysql -P 12345 -uroot
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

Even more details

  • I've seen that there's a question which looks like mine. However, it isn't the same (and it doesn't have any answers anyway)
  • I've seen that there are images dedicated to mysql, but I didn't have more success with them
  • My grep -v may feel weird. Admittedly, there may be cleaner way to do it. But when I attach my image, I can observe it actually worked as expected (ie: removed the bind-address). And I can see in the container /var/log/mysql/error.log:

Server hostname (bind-address): '0.0.0.0'; port: 3306 - '0.0.0.0' resolves to '0.0.0.0'; Server socket created on IP: '0.0.0.0'.

E_net4
  • 27,810
  • 13
  • 101
  • 139
gturri
  • 13,807
  • 9
  • 40
  • 57
  • 9
    Probably not so dumb. I stumbled upon this for the 10th time now and finally got the time to try it out at home. – kiltek Dec 17 '18 at 18:24
  • NOTE: some people may end up here, and want to connect to a mysql image run in docker, but the port isn't exposed. When you run it using the `docker run` command, make sure you open the port, like so, `docker run -p 3306:3306 ...` or you wont be able to connect. Of course this can be done in a Dockerfile too, but you don't need a custom docker image to do this! – Brad Parks Mar 10 '22 at 22:00
  • 1
    A note for people who, like me, store their dev credentials in a .my.cnf file and then wonder why they cannot connect with root: The password from .my.cnf will be used even when specifying `-p` without a value. To avoid that, `--no-defaults` worked for me. In full, `mysql --no-defaults --protocol=tcp -uroot -p`. – Dario Seidl Oct 31 '22 at 13:58

20 Answers20

340

If your Docker MySQL host is running correctly you can connect to it from local machine, but you should specify host, port and protocol like this:

mysql -h localhost -P 3306 --protocol=tcp -u root

Change 3306 to port number you have forwarded from Docker container (in your case it will be 12345).

Because you are running MySQL inside Docker container, socket is not available and you need to connect through TCP. Setting "--protocol" in the mysql command will change that.

adhg
  • 10,437
  • 12
  • 58
  • 94
jozala
  • 4,625
  • 2
  • 18
  • 15
  • 3
    Can you clarify why the mysql socket is not available? Your command works, but I'm wondering if there's a way to mount the mysql socket to the host from the container. – Lucas Apr 27 '17 at 20:28
  • 15
    I am not an expert in Unix communication, but from what I understand socket is a connection represented as a file. Since socket file is not shared between Docker container and host machine MySQL client cannot use one from inside of the Docker container. To connect to the MySQL server inside Docker container from host machine you could: 1. Set MySQL server to put socket in the specified place `--socket=/var/run/mysqld/mysqld.sock` 2. Mount this file outside of the Docker container 3. Specify path to socket in MySQL client with `--socket=/host/mysql.sock` – jozala May 01 '17 at 10:14
  • @maniekq Great comment! But did you verify all your three possibilities? Do they all really work? – Andru Feb 07 '18 at 16:10
  • 14
    After I long struggle I found this golden answer, `--protocol=tcp` finally made the connection work. Thanks @maniekq for both the nice answer and your explanation on sockets via your comment! – panepeter Feb 21 '18 at 09:47
  • 2
    It should not be the accepted answer, since he explicitly states that he has no idea of UNIX file communication. – kiltek Dec 17 '18 at 18:26
  • I believe that if you use the host `127.0.0.1` instead of `localhost` then you will be using the TCP stack instead of the unix socket, thus making the `--protocol` flag unnecessary. – dotancohen Jun 27 '19 at 15:00
  • 2
    This worked for me. I just needed to add `-p` at the end so MySQL will ask for a password. – asherbret Mar 29 '20 at 20:05
  • 1
    works fine without `protocol`, basically what i did is `mysql -h localhost -P 12345 -u root -p password` – Long May 13 '21 at 17:10
  • I did not have to set the protocol, works fine without protocol. But does mysql know to connect to container as what we are saying is localhost but the IP of the container could be different. Also the host and the container are not on the same network I presume? – serah Dec 28 '21 at 08:02
  • For other dumb-dumbs like myself, I gave detailed commands in a comment to @VasiliPascal's answer. – s3c Dec 02 '22 at 03:53
  • For me, using either `--protocol=tcp` _or_ `-h 127.0.0.1` did the trick. (I also needed the `-p` flag, bc I ran my container with `-e MYSQL_ROOT_PASSWORD=`. Thanks – Peter May 05 '23 at 13:47
110

If you use "127.0.0.1" instead of localhost mysql will use tcp method and you should be able to connect container with:

mysql -h 127.0.0.1 -P 3306 -u root
Vasili Pascal
  • 3,102
  • 1
  • 27
  • 21
  • 3
    I don't believe this is the case. Not downvoting because I'm not 100% sure, but in my experience localhost and 127.0.0.1 always attempt to use a socket unless you add --protocol=tcp – andrew lorien Jun 10 '18 at 01:26
  • 9
    I can verify that once i changed localhost to 127.0.0.1 and removed the protocol flag, it worked the same – Craig Wayne Aug 10 '18 at 14:13
  • 2
    I think this is the short and best answer ;) – rezam Sep 10 '18 at 19:19
  • 1
    Might be short but it's not the answer, given that TCP is the slower method to communicate with mysql. (more cpu and higher latency) – John Jan 21 '19 at 03:42
  • 1
    @John you are right, it's slower but it does exist. Of course you can share /var/run/mysqld/mysqld.sock between host and container. – Vasili Pascal Jan 21 '19 at 12:51
  • 2
    That's what I'd recommend for any higher duty DB. it's as simple as "-v socketfile.sock" and then mysql --socket /path/file.sock without polluting the tcp/ip stack. – John Jan 22 '19 at 18:14
  • 1
    Can confirm that using `127.0.0.1` for the host property fixes the error but using `localhost` leaves me with the same problem. On OSX 10.13.6 – Don Aug 15 '19 at 20:02
  • 1
    I'm using Rails and I had trouble running `rake db:setup` from outside docker connecting to the mysql database. Specifying the host `127.0.0.1` solves it. – Zack Xu Jan 08 '20 at 12:15
  • Note just for other stupids like myself: `docker ps` to list all containers; copy CONTAINER_ID of your DB container; `docker exec -it {CONTAINER_ID} bash`; copy DB_USERNAME and DB_PASSWORD from docker-compose.yaml; `mysql -h 127.0.0.1 -P 3306 -u {DB_USERNAME } -p` and type in `{DB_PASSWORD}`. Also `show databases;`, `use {DATABASE_NAME}`; `show tables;`, if you need. – s3c Dec 02 '22 at 03:52
52

I recommend checking out docker-compose. Here's how that would work:

Create a file named, docker-compose.yml that looks like this:

version: '2'

services:

  mysql:
    image: mariadb:10.1.19
    ports:
      - 8083:3306
    volumes:
      - ./mysql:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: wp

Next, run:

$ docker-compose up

Notes:

Now, you can access the mysql console thusly:

$ mysql -P 8083 --protocol=tcp -u root -p

Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 5.5.5-10.1.19-MariaDB-1~jessie mariadb.org binary distribution

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

Notes:

  • You can pass the -d flag to run the mysql/mariadb container in detached/background mode.

  • The password is "wp" which is defined in the docker-compose.yml file.

  • Same advice as maniekq but full example with docker-compose.

l3x
  • 30,760
  • 1
  • 55
  • 36
  • 4
    `--protocol=tcp` fixed everything for me. Thank you! – Charlie L Mar 14 '17 at 21:19
  • Thanks for this answer, I had same issue as in topic but after using --protocol=tcp it fixed. I thought something was wrong with docker network. – jiriki Mar 21 '20 at 15:03
  • You're welcome @tiago-elias. As a heads up, I hope to release another chapter, "Deep Data Analysis," in my book soon: https://leanpub.com/dataengineeringhandbook – l3x Sep 25 '20 at 19:10
  • Not setting the IP address explicitly did the trick for me, thank you! – Andresa Martins Sep 16 '21 at 04:10
21

The simple method is to share the mysql unix socket to host machine. Then connect through the socket

Steps:

  • Create shared folder for host machine eg: mkdir /host
  • Run docker container with volume mount option docker run -it -v /host:/shared <mysql image>.
  • Then change mysql configuration file /etc/my.cnf and change socket entry in the file to socket=/shared/mysql.sock
  • Restart MySQL service service mysql restart in docker
  • Finally Connect to MySQL servver from host through the socket mysql -u root --socket=/host/mysql.sock. If password use -p option
Jobin
  • 6,506
  • 5
  • 24
  • 26
  • 1
    Do you have to do this if the MySQL client is in another container ? – Stephane Oct 31 '17 at 07:02
  • 1
    I don't know that. I opted this method because tcp-ip port method didn't work for me. If you are using two containers for server and client, you can share a common directory to both containers and use Unix socket to connect to MySQL. – Jobin Nov 01 '17 at 14:43
  • 1
    The answer to my question is no when I use docker-compose with a link on the containers. – Stephane Nov 02 '17 at 15:37
  • This is working but connection using host is not – Arif Aug 07 '22 at 12:02
18

OK. I finally solved this problem. Here follows my solution used in https://sqlflow.org/sqlflow.

The Complete Solution

To make the demo self-contained, I moved all necessary code to https://github.com/wangkuiyi/mysql-server-in-docker.

The Key to the Solution

I don't use the official image on DockerHub.com https://hub.docker.com/r/mysql/mysql-server. Instead, I made my own by installing MySQL on Ubuntu 18.04. This approach gives me the chance to start mysqld and bind it to 0.0.0.0 (all IPs).

For details, please refer to these lines in my GitHub repo.

SQLFLOW_MYSQL_HOST=${SQLFLOW_MYSQL_HOST:-0.0.0.0}

echo "Start mysqld ..."
sed -i "s/.*bind-address.*/bind-address = ${SQLFLOW_MYSQL_HOST}/" \
    /etc/mysql/mysql.conf.d/mysqld.cnf
service mysql start

To Verify My Solution

  1. Git clone the aforementioned repo.
    git clone https://github.com/wangkuiyi/mysql-server-in-docker
    cd mysql-server-in-docker
    
  2. Build the MySQL server Docker image
    docker build -t mysql:yi .
    
  3. Start MySQL server in a container
    docker run --rm -d -p 23306:3306 mysql:yi
    
  4. Install the MySQL client on the host, if not yet. I am running Ubuntu 18.04 on the host (my workstation), so I use apt-get.
    sudo apt-get install -y mysql-client
    
  5. Connect from the host to the MySQL server running in the container.
    mysql --host 127.0.0.1 --port 23306 --user root -proot
    

Connect from Another Container on the Same Host

We can run MySQL client from even another container (on the same host).

docker run --rm -it --net=host mysql/mysql-server mysql \
   -h 127.0.0.1 -P 13306 -u root -proot

Connect from Another Host

On my iMac, I install the MySQL client using Homebrew.

brew install mysql-client
export PATH="/usr/local/opt/mysql-client/bin:$PATH"

Then, I can access the above Ubuntu host (192.168.1.22).

mysql -h 192.168.1.22 -P 13306 -u root -proot

Connect from a Container Running on Another Host

I can even run MySQL client in a container running on the iMac to connect to the MySQL server in a container on my Ubuntu workstation.

docker run --rm -it --net=host mysql/mysql-server mysql \
    -h 192.168.1.22 -P 13306 -u root -proot

A Special Case

In the case that we run MySQL client and server in separate containers running on the same host -- this could happen when we are setting up a CI, we don't need to build our own MySQL server Docker image. Instead, we can use the --net=container:mysql_server_container_name when we run the client container.

To start the server

docker run --rm -d --name mysql mysql/mysql-server

To start the client

docker run --rm -it --net=container:mysql mysql/mysql-server mysql \
 -h 127.0.0.1 -P 3306 -u root -proot
cxwangyi
  • 653
  • 1
  • 8
  • 15
10

if you running docker under docker-machine?

execute to get ip:

docker-machine ip <machine>

returns the ip for the machine and try connect mysql:

mysql -h<docker-machine-ip>
Gerardo Rochín
  • 309
  • 4
  • 9
8

In your terminal run: docker exec -it container_name /bin/bash Then: mysql

  • if u run on windows, u cannot run this on git-bash, but on cmd ms-dos – duchuy Dec 11 '20 at 05:11
  • 2
    The question asks how to connect from the host. The problem description states that they're able to connect from within the container. – Marvo Apr 19 '22 at 07:38
7

You should inspect the IP address assigned to the running container, and ther connect to that host:

docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container name or id>

than you can connect with:

mysql -h <IP provided by inspect command> -P <port> -u <user> -p <db name>

https://mariadb.com/kb/en/installing-and-using-mariadb-via-docker/#connecting-to-mariadb-from-outside-the-container

Enrico Ferreguti
  • 438
  • 4
  • 13
6
  • docker run -e MYSQL_ROOT_PASSWORD=pass --name sql-db -p 3306:3306 mysql

  • docker exec -it sql-db bash

  • mysql -u root -p

Wtower
  • 18,848
  • 11
  • 103
  • 80
Ajay Singh
  • 464
  • 6
  • 10
5

I do this by running a temporary docker container against my server so I don't have to worry about what is installed on my host. First, I define what I need (which you should modify for your purposes):

export MYSQL_SERVER_CONTAINER=mysql-db
export MYSQL_ROOT_PASSWORD=pswd 
export DB_DOCKER_NETWORK=db-net
export MYSQL_PORT=6604

I always create a new docker network which any other containers will need:

docker network create --driver bridge $DB_DOCKER_NETWORK

Start a mySQL database server:

docker run --detach --name=$MYSQL_SERVER_CONTAINER --net=$DB_DOCKER_NETWORK --env="MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD" -p ${MYSQL_PORT}:3306 mysql

Capture IP address of the new server container

export DBIP="$(docker inspect ${MYSQL_SERVER_CONTAINER} | grep -i 'ipaddress' | grep -oE '((1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])')"

Open a command line interface to the server:

docker run -it -v ${HOST_DATA}:/data --net=$DB_DOCKER_NETWORK --link ${MYSQL_SERVER_CONTAINER}:mysql --rm mysql sh -c "exec mysql -h${DBIP} -uroot -p"

This last container will remove itself when you exit the mySQL interface, while the server will continue running. You can also share a volume between the server and host to make it easier to import data or scripts. Hope this helps!

COwnby
  • 111
  • 2
  • 7
5
mysql -u root -P 4406 -h localhost --protocol=tcp -p

Remember to change the user, port and host so that it matches your configurations. The -p flag is required if your database user is configured with a password

Hamfri
  • 1,979
  • 24
  • 28
3

For conversion,you can create ~/.my.cnf file in host:

[Mysql]
user=root
password=yourpass
host=127.0.0.1
port=3306

Then next time just run mysql for mysql client to open connection.

lupguo
  • 1,525
  • 13
  • 13
2

I was able to connect mysql server 5.7 running on my host using the below command:

mysql -h 10.10.1.7 -P 3307 --protocol=tcp -u root -p  

where the ip given is my host ip and 3307 is the port forwaded in mysql docker. After entering the command type the password for mysql. That is it. Now you are connected the mysql docker container from the your host machine.

Wtower
  • 18,848
  • 11
  • 103
  • 80
Rajesh k
  • 37
  • 3
1

run following command to run container

docker run --name db_name -e MYSQL_ROOT_PASSWORD=PASS--publish 8306:3306 db_name

run this command to get mysql db in host machine

mysql -h 127.0.0.1 -P 8306 -uroot  -pPASS

in your case it is

mysql -h 127.0.0.1 -P 12345 -uroot  -pPASS
Vaibhav Vishal
  • 6,576
  • 7
  • 27
  • 48
Nitin
  • 69
  • 6
  • This only works if you use 127.0.0.1 as the address. If you use the host's non-local address you need to add the `--protocol=tcp` flag as described in several other comments/answers. In my case it was extra confusing because I had a local, non-dockerized, mysql instance running as well. By default, even when the port is specified, even if the port is incorrect, the 'mysql' command will connect via the socket file to the local instance. – Rich Apr 16 '20 at 16:02
  • @Rich so what did you do to solve that problem? Even I'm having similar setup, one MySql running on host and another in docker container. – NITHIN RAJ T Apr 21 '20 at 09:35
  • @NITHINRAJT there are 2 ways to accomplish this AFTER you make sure your docker instance isn't listening on the same port (e.g., like in this answer, 8306). (1) Try this answer, the one we're commenting on (e.g., connecting to 127.0.0.1. (2) Try the next answer - `mysql -u root -P -h --protocol=tcp -p`. The flag, `--protocol=tcp` is the key to making this work. – Rich Apr 22 '20 at 16:14
1

First, see the logs Are there any errors or not.

docker ps -a
docker logs container_name

If there is any error, search for the solution of that particular error, if there are no errors you may proceed to the next step.

Remember after starting your container MySQL take a few minutes to start so run those commands after 3-4 minutes.

docker exec -it container_name bash
# ONCE YOU ARE INSIDE CONTAINER 
mysql -u root -p
SHOW DATABASES;
exit

To connect from terminal or command prompt

mysql -h localhost -P 3306 --protocol=tcp -u root -p
MD SHAYON
  • 7,001
  • 45
  • 38
1

I have tried the same thing, and I was facing same problem, but I have noticed one thing, whenever I was trying to run docker container with /bin/bash like as below:

docker container run -it --name test_mysql -e MYSQL_ROOT_PASSWORD=password -p 3306:3306 mysql:latest /bin/bash

After hitting the above command, my container getting start but facing the same error" ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)"

Now, I have tried instead of above command, I have used below command:

docker container run -itd --name test_mysql -e MYSQL_ROOT_PASSWORD=password -p 3306:3306 mysql:latest

docker container exec test_mysql /bin/bash

then using the command

mysql -uroot -P3306 -p

then able to connect, Hope This idea will work in your case.

Thanks Love Arora

Erenn
  • 625
  • 6
  • 18
love arora
  • 11
  • 2
0

According to the photos, go to the project -> MySQL -> inspect tab in the docker desktop app and modify the information about the database .env file.

.env file example:

DB_CONNECTION=mysql
DB_HOST=0.0.0.0:3306
DB_PORT=3306
DB_DATABASE=testdb
DB_USERNAME=sail
DB_PASSWORD=password

enter image description here

enter image description here

buddemat
  • 4,552
  • 14
  • 29
  • 49
0

In case this will help somebody:

My prefered solution

add ~/.my.cnf with contents

[client]
user=<yourusername>
password=typethepasswordhere
host=127.0.0.1
port=3306

then from the terminal run >$ mysql and you should get in your sql cmd.

The hardcore alternative

you can also connect like this

docker exec -it containername mysql  

To get into the sql cmd

or

docker exec -it contaiinername bash (or sh) 

to connect in the container and then run >$ mysql

0

None of the other answers worked for me running on Ubuntu 22.04.2 LTS but I finally cobbled together a way to get connected.

First of all, I followed the docs to get the Docker Container running MySql 8.1 Enterprise server at this official MySql link.

Next, I had to create a new container like the following to expose MySql:

docker run --name=mysql1 -p 3306:3306 -d container-registry.oracle.com/mysql/enterprise-server:8.1

I discovered this command here in this SO answer.

After that when I ran the command $ sudo docker container list I saw something like the following:

e733323573 container-registry.oracle.com/mysql/enterprise-server:8.1 "/entrypoint.sh mysq…" 23 hours ago Up 6 hours
0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060-33061/tcp mysql1

The emphasis is on the bold part, because before that the ports didn't show up.

I assumed this meant that MySql was exposed me via 0.0.0.0:3306 or 127.0.0.1:3306 because that was what everyone was saying.

However, I discovered (very painfully ala trial & error) that this wasn't true.

I then discovered the next part I needed on this SO answer.

I needed to allow the "outer" IP Address to MySql which is running in the Docker instance.

  1. So I started up the Docker instance.
  2. Logged into MySql as root.
  3. SELECT host FROM mysql.user WHERE User = 'root';

When you run the select command you'll probably see something like the following:

+------------+
| host       |
+------------+
| localhost  |
+------------+

That means that a user named root, coming from 127.0.0.1 will be able to log in.

However, in our case my ASP.NET Core 6.x WebAPI will be attempting to access the Docker Container from a different address.

How Can You See The Docker Container Address? $ sudo docker inspect <your-docker-instance-name> In the case of the one above we will run the following:

$ sudo docker inspect mysql1

When that runs you will see some JSON that contains something like the following:

"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",

The Gateway address is actually the one you want to add to your MySql user table so that a user from outside the Docker container can connect.

So, once you're logged into MySql in the Docker container as root, you can do the following (the password between single-quotes will be your password, of course):

CREATE USER 'root'@'172.17.0.1' IDENTIFIED BY 'some_pass';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'172.17.0.1';
FLUSH PRIVILEGES;

If you do that initial query again, you should now see:

+------------+
| host       |
+------------+
| 172.17.0.1 |
| localhost  |
+------------+

Now, you can create a proper connection string using the ip address (not the Gateway address) from above and it "should" work.

Server=172.17.0.2;Database=<your-db-name>;port=3306;uid=root;pwd=some-pass;SslMode=preferred;

So, what you've done is allowed traffic from the Gateway address ( 172.17.0.1) to connect to MySql and you've connected to MySql by connecting to the Ip Address (172.17.0.2) of MySql Docker Container.

That's it. It finally all worked.

If It Still Doesn't Allow Access

If you still can't get connected you can try opening up all access (all ip addresses on all DBs & Tables):

CREATE USER 'root'@'%' IDENTIFIED BY 'some_pass';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';
raddevus
  • 8,142
  • 7
  • 66
  • 87
-7

change "localhost" to your real con ip addr
because it's to mysql_connect()