Docker MySQL

When setting up a local development environment, MySQL remains one of the most reliable and widely adopted relational databases. Traditionally, installing MySQL directly on your operating system often leads to frustrating issues such as version conflicts, complex configuration steps, and leftover files upon uninstallation. By leveraging Docker, developers can spin up a clean, reproducible, and easily disposable MySQL instance with just a few commands. This guide explores the complete setup process and industry best practices.

  • Environment Consistency: Docker images lock down the exact MySQL version, eliminating the classic "it works on my machine" dilemma across team members and testing stages.
  • Rapid Deployment: Start a fully functional instance with a single command, and wipe it clean by simply removing the container without leaving clutter on your host machine.
  • Multi-Version Coexistence: Run multiple instances, such as MySQL 5.7 and 8.0, simultaneously by mapping them to different host ports.
  • Seamless Integration: Effortlessly orchestrate MySQL alongside your application code and caching services like Redis using Docker Compose.
    Before diving in, make sure Docker is installed and running on your system. You can verify your installation by executing:
docker --version
docker info

If both commands return the expected version and system details, your Docker environment is ready.

Pulling the MySQL Image

Pull the desired MySQL version from Docker Hub. It is strongly recommended to specify an explicit version tag rather than using latest to ensure long-term environment stability:

docker pull mysql:8.0

Once the download is complete, you can inspect your local image repository using docker images.

Launching the MySQL Container

Use the docker run command to spin up a fresh MySQL development instance:

docker run -d \
  --name mysql-dev \
  -e MYSQL_ROOT_PASSWORD=123456 \
  -e MYSQL_DATABASE=demo \
  -e MYSQL_USER=devuser \
  -e MYSQL_PASSWORD=devpass \
  -p 3306:3306 \
  -v mysql-data:/var/lib/mysql \
  mysql:8.0

Here is a breakdown of the key parameters:

  • -d: Runs the container in detached mode in the background.
  • --name: Assigns a custom name to the container for easier management.
  • -e MYSQL_ROOT_PASSWORD: Sets the administrative root password (mandatory, otherwise the container will fail to start).
  • -e MYSQL_DATABASE: Automatically creates a database named demo upon initial startup.
  • -e MYSQL_USER and -e MYSQL_PASSWORD: Creates a standard non-root user, promoting better security habits for daily development.
  • -p 3306:3306: Maps port 3306 on your host machine to port 3306 inside the container.
  • -v mysql-data:/var/lib/mysql: Mounts a named volume to persist database files safely.

Data Persistence and Configuration Mounting

Containers are inherently ephemeral, meaning any data written inside them disappears when the container is removed. Thanks to the -v flag mentioned above, your data is safely stored in a named volume called mysql-data, ensuring persistence even if the container is destroyed and recreated.

If you need to customize MySQL settings—such as adjusting the maximum allowed connections—you can mount a local configuration file directly into the container:

-v /path/to/my.cnf:/etc/mysql/conf.d/my.cnf

Connecting and Verifying

After launching the container, allow roughly ten to fifteen seconds for the initialization process to finish. Then, access the built-in MySQL client inside the container:

docker exec -it mysql-dev mysql -uroot -p

Enter your password and run the following commands to confirm everything is working:

SHOW DATABASES;
USE demo;
SELECT VERSION();

Alternatively, you can connect from external GUI tools like Navicat, DataGrip, or your local mysql command-line utility by targeting 127.0.0.1:3306.

Orchestration with Docker Compose

When your development stack involves multiple services, or when you want to keep your environment configurations version-controlled, Docker Compose is the ideal choice. Create a docker-compose.yml file in your project root:

services:
  mysql:
    image: mysql:8.0
    container_name: mysql-dev
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: "123456"
      MYSQL_DATABASE: demo
    command:
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_unicode_ci
    ports:
      - "3306:3306"
    volumes:
      - mysql-data:/var/lib/mysql
      - ./init:/docker-entrypoint-initdb.d

volumes:
  mysql-data:

Essential commands for managing your stack:

docker compose up -d      # Start services in the background
docker compose down       # Stop and remove containers
docker compose logs -f    # Tail container logs

Any .sql script placed inside the ./init directory will execute automatically during the initial startup, making it exceptionally convenient for bootstrapping table schemas and seed data.

Common Operational Commands

  • View container logs: docker logs -f mysql-dev
  • Stop and start the container: docker stop mysql-dev and docker start mysql-dev
  • Backup the database: docker exec mysql-dev mysqldump -uroot -p123456 demo > backup.sql
  • Restore the database: docker exec -i mysql-dev mysql -uroot -p123456 demo < backup.sql

Troubleshooting and Best Practices

  1. Port Conflicts: If port 3306 is already bound on your host machine, change the port mapping to -p 3307:3306 and connect your clients to port 3307.
  2. Character Set Issues: Default character sets may not support international text properly; explicitly enforce utf8mb4 using the command arguments.
  3. Slow First Startup: Initializing the data directory takes a brief moment. If connection attempts fail initially, check the container logs to verify its readiness status.
  4. Password Security: The weak passwords used in examples are meant strictly for local development. Never use them in production, and consider injecting sensitive credentials via .env files or secrets managers.

By following these steps, you have established an isolated, persistent, and version-controllable MySQL development environment. As your projects grow to include master-slave replication or multi-instance testing, you can easily scale these configurations outward.