Skip to content

Install MySQL With PhpMyAdmin Using Docker

6 min read

Do these errors look familiar to you?

MySQLInterfaceError: Can't connect to MySQL server on 'mysql'

mysqli::real_connect(): (HY000/2002): php_network_getaddresses: getaddrinfo failed: Name or service not known

Frustrating, I know.

Why is it so difficult to simply connect to a MySQL database? You could fix it if you delve deep into networking, but who has time for that?

Or maybe you just want to quickly install MySQL, without bloating your machine, and continue working on your application.

By the end of this tutorial, you will have clean installs of MySQL and phpMyAdmin that are configured properly to just work. You'll accomplish this with minimal effort using a single command to start the entire application stack.

Let's get started!

Requirements
You don't need a lot of knowledge or tools to be able to follow along with this tutorial. What you'll need is:

  • Docker installed on your machine. The official docs have an installation guide for macOS, Windows and Linux operating systems.
  • (Optional) Docker Compose. It comes bundled with Docker Desktop.

Verify you have both installed by typing docker -v and docker-compose -v in your terminal. You should see a similar output:

$ docker -v
Docker version 19.03.8, build afacb8b
$ docker-compose -v
docker-compose version 1.25.4, build 8d51620a

Basic experience using the Docker command line is useful, but not required. We'll go over each step in detail and explain what we're doing.

Goals
Without phpMyAdmin or MySQL preinstalled, our goal is to quickly have a local phpMyAdmin webserver running that's connected to a MySQL database. We will download and run both through Docker, and configure them so they can communicate properly.

As a bonus, you will see how to accomplish this with just one file and a single command using Docker Compose.

Step 1 — Installing MySQL

Let's start by installing the MySQL database first. We need to have it up & running before we can connect with phpMyAdmin.

We'll grab the image from the official MySQL repository on Docker Hub using docker pull command. As of writing, the latest version of MySQL is 8.0.19. If you want to use MySQL 5, that will work as well.

# Download MySQL 8.0.19 image from Docker Hub
docker pull mysql:8.0.19

You should see several progress bars and after a while it should have finished successfully:

Digest: sha256:b69d0b62d02ee1eba8c7aeb32eba1bb678b6cfa4ccfb211a5d7931c7755dc4a8
Status: Downloaded newer image for mysql:8.0.19
docker.io/library/mysql:8.0.19

With the MySQL image downloaded, let's run a container from it with the docker run command. We'll give the container a name with the --name flag and have it run in the background with the -d flag, so we can keep using the same terminal window for subsequent commands.

MySQL requires us to provide a password for the root database user to start the database. We can do this by assigning the password to the MYSQL_ROOT_PASSWORD environment variable which we'll pass on to the container. Docker allows you to pass environment variables with the -e flag. Our command to start MySQL is:

# Start a MySQL container
docker run --name mysql -d -e MYSQL_ROOT_PASSWORD=my-secret-pw mysql:8.0.19

Run this command, and you should see a random and long string displayed. That's the unique ID assigned to the container by Docker. It means MySQL is successfully up and running.

To verify this, we can list all running containers with docker ps:

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                 NAMES
4e61b2cba425        mysql:8.0.19        "docker-entrypoint.s…"   3 seconds ago       Up 3 seconds        3306/tcp, 33060/tcp   mysql

Step 2 — Installing phpMyAdmin

Now we're ready to move on to phpMyAdmin. Let's download it from the phpMyAdmin repository on Docker Hub. At the moment of writing, 5.0.2 is the latest version. We'll use the docker pull command again:

# Download phpMyAdmin 5.0.2
docker pull phpmyadmin/phpmyadmin:5.0.2

After some time, you should see a successful download:

Digest: sha256:46dfe47ca8d3a172e7a203049bd33f516b179dc4a7205a88a97ba0bf9fc94c11
Status: Downloaded newer image for phpmyadmin/phpmyadmin:5.0.2
docker.io/phpmyadmin/phpmyadmin:5.0.2

Similarly to MySQL, we run this container with the --name and -d flags. We give it a different name because container names have to be unique.

phpMyAdmin uses the PMA_HOST environment variable to know where to connect to the MySQL database. We set this variable to be equal to the MySQL container name, namely mysql. I explain why in the next section, where we will create a Docker network.

Moreover, we're going to map port 8080 on the host to port 80 inside the container. The host is simply the operating system where you've installed Docker. Mapping a port from the host to the container means that when we go to localhost:8080 (in the browser for example), we want that to point to port 80 inside the phpMyAdmin container. To map a port, we use the -p flag, and the syntax is -p <HOST_PORT>:<CONTAINER_PORT>.

Let's see all of the above in action:

# Start a phpMyAdmin container
docker run --name phpmyadmin -d -p 8080:80 -e PMA_HOST=mysql phpmyadmin/phpmyadmin:5.0.2

We use port 80 because that's the port the phpMyAdmin web server is listening on for incoming requests. Port 8080 on the host is chosen randomly and doesn't have a particular meaning. We could've used any available port on the host.

Let's verify both containers are running side to side with docker ps:

$ docker ps
CONTAINER ID        IMAGE                         COMMAND                  CREATED             STATUS              PORTS                  NAMES
8980917d10d0        phpmyadmin/phpmyadmin:5.0.2   "/docker-entrypoint.…"   38 minutes ago      Up 38 minutes       0.0.0.0:8080->80/tcp   phpmyadmin
4e61b2cba425        mysql:8.0.19                  "docker-entrypoint.s…"   2 hours ago         Up 2 hours          3306/tcp, 33060/tcp    mysql

Step 3 — Creating a Docker network

There is one last thing left for us to do before we can navigate to the phpMyAdmin dashboard. At this point, phpMyAdmin can't connect to MySQL because the mysql hostname we used in the previous step doesn't translate to the IP address of the MySQL container.

Translating hostnames to IP addresses is called DNS resolution. Fortunately, Docker provides DNS resolution out of the box when we create a network. All containers inside that network will be able to communicate with each other using their names. Let's create a network:

# Create a Docker network
docker network create my-network

Now, let's connect both MySQL and phpMyAdmin containers to this network.

# Connect MySQL and phpMyAdmin containers to our network
docker network connect my-network mysql
docker network connect my-network phpmyadmin

You won't see anything printed out in the console, which is good. It means both containers are now part of our network and can communicate with each other using their names.

Navigate to localhost:8080 in your browser, and log in with username: root and password: my-secret-pw. You should now be inside the phpMyAdmin dashboard. Hooray 🎉.

Step 4 — (Bonus) Using Docker Compose

Docker Compose is a tool for defining and running multi-container Docker applications. With Compose, you use one file to configure all of your application's containers. Then, with a single command, you create and start all containers from your configuration. In our case, the application stack is two containers and a network that connects them.

The naming convention for the configuration file is docker-compose.yml. Inside the file, containers are defined as services. Let's combine all the steps from this tutorial and put them in a single file:

# We're using version 3.7 of the Docker Compose file format
version: "3.7"

# Define services/containers
services:
  # MySQL container
  mysql:
    # Use mysql:8.0.19 image
    image: mysql:8.0.19
    # Connect to "my-network" network, as defined below
    networks:
      - my-network
    # Pass a list of environment variables to the container
    environment:
      MYSQL_ROOT_PASSWORD: my-secret-pw

  # phpMyAdmin container
  phpmyadmin:
    # Use phpmyadmin/phpmyadmin:5.0.2 image
    image: phpmyadmin/phpmyadmin:5.0.2
    # Connect to "my-network" network, as defined below
    networks:
      - my-network
    # Map port 8080 on the host to port 80 inside the container
    # Syntax is: "HOST_PORT:CONTAINER_PORT"
    ports:
      - "8080:80"
    # Pass a list of environment variables to the container
    environment:
      PMA_HOST: mysql
    # Wait for "mysql" container to start first
    depends_on:
      - mysql

# Define networks
networks:
  my-network:

When you pay close attention to each line, you can see how this translates to the commands we ran in previous steps. We define two containers, mysql and phpmyadmin. For each container, we use a combination of keys and values instead of flags to configure them.

You might've noticed a configuration key we haven't used in our commands before: depends_on. With this, we tell Docker Compose that phpMyAdmin relies on MySQL and it should start MySQL container first. This chronological startup sequence prevents connection problems from phpMyAdmin to a MySQL database that hasn't finished initialising yet.

To start the application stack, in the same folder as the docker-compose.yml file, run:

# Start the application stack defined in docker-compose.yml
docker-compose up -d

Similar to docker run, the -d flag lets us run our application stack in the background. The command to stop and remove all containers and networks is:

# Stop the application stack
docker-compose down

Conclusion

We ended up with a setup that has MySQL and phpMyAdmin running inside different containers connected through a shared network. Additionally, Docker Compose allows us to quickly start the entire application stack by using just a single command.

Write clean code. Stay ahead of the curve.

Every other Tuesday, I share tips on how to build robust Node.js applications. Join a community of 1,526 developers committed to advancing their careers and gain the knowledge & skills you need to succeed.

No spam! 🙅🏻‍♀️ Unsubscribe at any time.

You might also like

Process Signals Inside Docker Containers

Handling process signals inside Docker containers can be tricky. Here's what to look out for.
Read article

A Beginner's Guide to Building a Docker Image of Your Node.js Application

In this article you'll learn how to create a Docker image to deploy your Node.js application.
Read article

Docker Compose Syntax: Volume or Bind Mount?

Docker Compose syntax for volumes is confusing. After reading this article you won't have to guess anymore.
Read article