Installing MySQL the traditional way means downloading an installer, configuring a system service, fighting with version conflicts if you already have another database installed, and hoping the uninstall process is actually clean when you’re done. Running MySQL with Docker skips all of that. One command pulls a ready-to-run MySQL server into an isolated container, and when you’re done experimenting, one more command removes it completely — no leftover files, no orphaned services, no registry entries.

This guide covers everything a beginner needs to start running MySQL databases in containers: pulling and starting the official MySQL image, setting the environment variables that configure it, persisting your data with volumes so it survives a container restart, connecting to it from a client or application, and managing it all with Docker Compose. By the end, you’ll be comfortable spinning up a disposable MySQL instance for local development in under a minute.

Why Run MySQL in Docker?

Containerizing your database brings a handful of concrete advantages over a traditional local install:

  • Isolation: Your MySQL container doesn’t touch your host machine’s filesystem or conflict with other database versions you might have installed.
  • Disposability: Made a mess experimenting with a schema? Delete the container and start a fresh one in seconds — no uninstall wizard required.
  • Consistency: The exact same MySQL version and configuration runs on your laptop, a teammate’s machine, and your CI pipeline.
  • Multiple versions side by side: Need MySQL 5.7 for one project and MySQL 8 for another? Run both at once on different ports without either installation interfering with the other.
  • Easy cleanup: docker rm removes the container; removing the associated volume removes the data. Nothing lingers on your system afterward.

Before You Start

You’ll need Docker installed and running on your machine (Docker Desktop on Windows/Mac, or Docker Engine on Linux). Confirm it’s working with:

docker --version

You don’t need to install MySQL itself at all — the container brings its own complete MySQL server, so there’s nothing else to set up beforehand.

Running Your First MySQL Container

The official MySQL image is maintained on Docker Hub and is the starting point for almost every MySQL-in-Docker setup. Start a container with:

docker run --name my-mysql \
  -e MYSQL_ROOT_PASSWORD=change-me \
  -p 3306:3306 \
  -d mysql:8.0

Breaking down each flag:

  • --name my-mysql — gives the container a friendly name so you can reference it later instead of a random ID.
  • -e MYSQL_ROOT_PASSWORD=change-me — required. The official image refuses to start without a root password (or an explicit opt-out flag), so this is the one environment variable you can’t skip.
  • -p 3306:3306 — maps port 3306 on your host to port 3306 inside the container, MySQL’s default port, so client tools on your machine can reach it.
  • -d — runs the container in detached mode, in the background, so your terminal stays free.
  • mysql:8.0 — the image and tag. Pinning a specific version (8.0) instead of latest means your setup won’t silently change when a new MySQL major version is released.

Check that it started successfully:

docker ps
docker logs my-mysql

The logs will show MySQL’s startup sequence and end with a line like ready for connections once it’s up.

Useful Environment Variables

Beyond the required root password, the official image accepts several other environment variables that configure the database on first startup:

  • MYSQL_DATABASE — creates a database with this name automatically on first run.
  • MYSQL_USER / MYSQL_PASSWORD — creates a non-root user with access to the database named in MYSQL_DATABASE.
  • MYSQL_ALLOW_EMPTY_PASSWORD — allows starting with no root password at all. Convenient for a quick throwaway container, never appropriate for anything you’d call “real.”

A more complete first run for a typical local project:

docker run --name my-mysql \
  -e MYSQL_ROOT_PASSWORD=change-me \
  -e MYSQL_DATABASE=app_db \
  -e MYSQL_USER=app_user \
  -e MYSQL_PASSWORD=app_password \
  -p 3306:3306 \
  -d mysql:8.0

This gives you a ready-to-use app_db database and an app_user account scoped to it, without ever touching the root account from your application.

Persisting Your Data with Volumes

Here’s the detail that trips up almost everyone new to running MySQL in Docker: by default, a container’s filesystem is ephemeral. Stop and remove the container, and every table, row, and schema you created disappears with it. To keep your data around, mount a volume at MySQL’s data directory, /var/lib/mysql.

Named volume (recommended for most cases):

docker run --name my-mysql \
  -e MYSQL_ROOT_PASSWORD=change-me \
  -v mysql-data:/var/lib/mysql \
  -p 3306:3306 \
  -d mysql:8.0

Docker creates and manages the mysql-data volume for you. It persists even if you remove the container, and you can reattach it to a new container later with the same -v flag.

Bind mount (when you want the data files on your host for easy backups or inspection):

docker run --name my-mysql \
  -e MYSQL_ROOT_PASSWORD=change-me \
  -v ~/mysql-data:/var/lib/mysql \
  -p 3306:3306 \
  -d mysql:8.0

This writes MySQL’s actual data files to ~/mysql-data on your host machine. It’s easier to back up with a simple file copy, but it ties the container to that specific host path.

Either way, the rule to remember is simple: if /var/lib/mysql isn’t mounted to a volume, your data isn’t surviving a docker rm.

Connecting to Your MySQL Container

From inside the container, using the MySQL client that ships with the image:

docker exec -it my-mysql mysql -u root -p

You’ll be prompted for the root password, then dropped into a normal mysql> prompt.

From your host machine, using any MySQL client you already have installed (MySQL Workbench, DBeaver, the mysql CLI, or a programming language’s MySQL driver), connect to:

  • Host: 127.0.0.1 (or localhost)
  • Port: 3306 (or whatever host port you mapped with -p)
  • Username/password: whatever you set with MYSQL_USER/MYSQL_PASSWORD, or root with MYSQL_ROOT_PASSWORD

From another container on the same Docker network, reference the MySQL container by its --name as the hostname instead of 127.0.0.1 — Docker’s internal DNS resolves container names automatically for containers sharing a network.

Using Docker Compose for MySQL

Typing out long docker run commands gets old fast, and most real projects pair MySQL with an application container anyway. Docker Compose lets you define the whole setup in one file.

docker-compose.yml:

services:
  db:
    image: mysql:8.0
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: change-me
      MYSQL_DATABASE: app_db
      MYSQL_USER: app_user
      MYSQL_PASSWORD: app_password
    ports:
      - "3306:3306"
    volumes:
      - mysql-data:/var/lib/mysql

volumes:
  mysql-data:

Start it with:

docker compose up -d

Stop it (without deleting the volume) with:

docker compose down

Notice that down removes the container but leaves the named mysql-data volume intact, so your data is waiting for you the next time you run docker compose up -d. Add -v to docker compose down only when you explicitly want to wipe the data too.

Best Practices for Running MySQL in Docker

  • Pin a version tag. Use mysql:8.0 rather than mysql:latest, so an unrelated docker pull doesn’t suddenly upgrade you to a new major version mid-project.
  • Always mount a volume. Treat an unmounted /var/lib/mysql as a guarantee that you will lose data eventually.
  • Keep secrets out of version control. Pass passwords via an .env file (excluded from Git) or Docker secrets rather than hardcoding them in a committed docker-compose.yml.
  • Don’t expose port 3306 publicly on a server with a public IP unless you have a specific reason to and a firewall rule restricting who can reach it. For most setups, only your application container needs access, over the internal Docker network.
  • Back up the volume, not just the container. A quick mysqldump run on a schedule, piped to a file outside the container, is enough for most small projects.
  • Give the container real resource limits (--memory, --cpus) if it’s running alongside other services on a shared host, so one runaway query can’t starve everything else.

Common Mistakes to Avoid

  • Forgetting the volume, then being surprised data is gone. This is by far the most common MySQL-in-Docker mistake — the container “worked fine” right up until it was recreated.
  • Reusing the same container name without removing the old one first. docker run --name my-mysql ... fails with a “name already in use” error if a stopped container still holds that name; remove it first with docker rm my-mysql.
  • Connecting to the wrong port after remapping it. If you map -p 3307:3306, your host-side clients need to connect on 3307, not 3306 — the left side of the mapping is always the host port.
  • Running the app and the database with mismatched networking, such as an app container trying to reach MySQL at 127.0.0.1 instead of the database container’s service name — 127.0.0.1 inside a container refers to that container itself, not the host or a sibling container.

Final Thoughts: Your Database, Fully Disposable

Running MySQL in Docker turns a once-fiddly local setup into a single command you can tear down and rebuild whenever you want. The two ideas worth keeping in mind are the ones beginners most often forget: the -e MYSQL_ROOT_PASSWORD environment variable is required to get a container running at all, and a volume mounted at /var/lib/mysql is what separates a database you can trust with real data from one that’s one docker rm away from losing everything.

Start small — pull the image, run a container with a named volume, and connect to it with a client you already know. Once that feels natural, move the setup into a docker-compose.yml alongside your application container, and you’ll have a fully reproducible local database environment that starts and stops with a single command, every time.