Skip to main content

MySQL with Docker

This guide shows how to run MySQL in Docker for development and small projects. You'll learn the essential commands, a docker-compose example, how to persist data safely, how to connect, and common pitfalls to avoid.

Concept explained

  • A MySQL Docker image packages the database server; the container runs the MySQL daemon process.
  • Persistent data must live outside the container filesystem – use Docker volumes (recommended) or host mounts.
  • Credentials and initialization can be supplied with environment variables or init scripts.
  • For production, prefer managed databases or a PaaS-provided MySQL for backups, monitoring and high availability.

Step-by-step example

  1. Run a single MySQL container (quick start)
docker network create app_network

docker volume create mysql_data

docker run -d \
--name mysql-dev \
--network app_network \
-e MYSQL_ROOT_PASSWORD=rootsecret \
-e MYSQL_DATABASE=appdb \
-e MYSQL_USER=appuser \
-e MYSQL_PASSWORD=userpass \
-v mysql_data:/var/lib/mysql \
-p 3306:3306 \
mysql:8.0
  • Replace passwords with secure values.
  • The named volume mysql_data holds the DB files so data survives container restarts.
  1. Connect with mysql client from the host (if mysql client is installed)
mysql -h localhost -P 3306 -u appuser -puserpass appdb
  1. Exec into the running container to use the bundled mysql client
docker exec -it mysql-dev mysql -u appuser -puserpass appdb
  1. Minimal docker-compose.yml (recommended for multi-service apps)
services:
db:
image: mysql:8.0
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: strongrootpass
MYSQL_DATABASE: appdb
MYSQL_USER: appuser
MYSQL_PASSWORD: stronguserpass
volumes:
- mysql_data:/var/lib/mysql
networks:
- app_network

volumes:
mysql_data:

networks:
app_network:

Start with: docker compose up -d db

Variations & gotchas

  • Init scripts: put .sql or .sh files in a folder mounted to /docker-entrypoint-initdb.d – they only run on first initialization.
  • Character sets: MySQL 8.0 defaults to utf8mb4. For older compatibility, you may need to configure charset explicitly.
  • Authentication: MySQL 8.0 uses caching_sha2_password by default; some older clients need mysql_native_password.
  • Versions: avoid the latest tag. Pin a major/minor version (e.g., mysql:8.0) to prevent surprises on updates.
  • Healthchecks: add a healthcheck in docker-compose to ensure MySQL is ready before your app starts.
# healthcheck example
db:
image: mysql:8.0
healthcheck:
test:
[
"CMD",
"mysqladmin",
"ping",
"-h",
"localhost",
"-u",
"root",
"-p$$MYSQL_ROOT_PASSWORD",
]
timeout: 10s
retries: 5
start_period: 30s
caution

If you change the volume path or recreate the volume, you can lose data. Always back up important databases before volume operations.

Common mistakes

  • Exposing 3306 publicly without firewall rules or strong passwords.
  • Using weak passwords or committing them into git.
  • Running migrations while MySQL isn't fully ready (use healthchecks/wait-for scripts).
  • Not setting proper character encoding for international text.
  • Using MYSQL_ALLOW_EMPTY_PASSWORD=yes in anything beyond local testing.

Best practices

  • Use named Docker volumes for persistence.
  • Pin image versions (e.g., mysql:8.0).
  • Keep production credentials in a secret manager or the PaaS secrets feature rather than plain files.
  • Schedule regular backups using mysqldump and test restores.
  • Set appropriate max_connections, innodb_buffer_pool_size for your workload.
  • Use specific users with limited privileges instead of root for application connections.

Example backup command:

docker exec mysql-dev mysqldump -u root -prootsecret appdb > backup.sql

Example restore:

docker exec -i mysql-dev mysql -u root -prootsecret appdb < backup.sql
tip

For local development, consider using a .env file for database credentials and add it to .gitignore.

When to use / when not to use

When to use:

  • Local development, testing, small internal projects, or prototypes.
  • When you want a lightweight DB alongside your app in Docker Compose.
  • Legacy applications that specifically require MySQL compatibility.

When not to use:

  • High-availability production systems requiring automated backups, replicas, or managed maintenance – prefer a managed DB or the PaaS database service.

Key takeaways

  • Run MySQL in Docker using a pinned image, named volume, and explicit credentials.
  • Use healthchecks and wait-for logic so apps connect only after MySQL is ready.
  • Don't expose MySQL directly to the public internet; secure credentials and regular backups are essential.
  • Consider character encoding and authentication plugin compatibility with your application stack.