Skip to main content

VillageSQL is a drop-in replacement for MySQL with extensions.

All examples in this guide work on VillageSQL. Install Now →
The official MySQL Docker image lets you run a fully configured MySQL server in a container. It handles initialization, user creation, and data directory setup automatically through environment variables.

Quick Start

Connect from the host machine:
Or connect inside the container:

Environment Variables

MYSQL_USER and MYSQL_PASSWORD must be set together. The created user receives full access to MYSQL_DATABASE.

Persistent Data with Volumes

Without a volume, all data is lost when the container is removed. Mount a volume to persist the data directory:
Named volume (mysql-data) persists across container restarts and removals. To use a host directory instead:
The data directory owns MySQL’s data and logs. Never share a volume between two running MySQL containers.

Choosing an Image and Volume Strategy

For most workloads, named volumes are the right default. Bind mounts are useful when you need to inspect or edit the data directory directly from the host, but the performance cost matters on macOS and Windows.

Docker Compose

For development environments with multiple services, Docker Compose is the standard approach:
The healthcheck with depends_on: condition: service_healthy ensures the application container doesn’t start until MySQL is ready to accept connections — not just started.

Custom Configuration

Pass a custom my.cnf by mounting it:
Or set options directly via command arguments:

Initialization Scripts

The container runs any .sql or .sh files placed in /docker-entrypoint-initdb.d/ on first startup (when the data directory is empty):
SQL files are executed as root. Shell scripts run in the container environment. These scripts only run on the very first initialization — not on subsequent container starts.

Connecting from Applications

Inside a Docker Compose network, containers connect to MySQL by service name:
From the host machine, connect via 127.0.0.1 (not localhost — MySQL’s socket isn’t available on the host):

When to Run MySQL in Docker

Production Considerations

Docker works well for MySQL in production with a few caveats:
  • Data persistence: Use named volumes or bind mounts. Never let MySQL data live in the container layer.
  • Memory limits: Set --memory in Docker to prevent MySQL from exhausting host memory, and tune innodb_buffer_pool_size to match.
  • Backups: mysqldump works inside the container: docker exec mysql-dev mysqldump -u root -p myapp > backup.sql
  • Logging: MySQL logs go to stdout/stderr in Docker. Use docker logs mysql-dev or configure your logging driver.
  • Upgrades: Pull the new image tag, stop the old container, and start the new one with the same volume. MySQL’s upgrade process runs automatically on first start with a newer version.

Frequently Asked Questions

Why can’t I connect with mysql -h localhost from the host?

On Linux and macOS, localhost causes the MySQL client to try connecting via Unix socket, which isn’t available on the host. Use 127.0.0.1 explicitly: mysql -h 127.0.0.1 -P 3306.

How do I make MySQL data persist in Docker?

Mount a named volume to /var/lib/mysql when you start the container: -v mysql-data:/var/lib/mysql. Without this, all data is stored in the container’s writable layer and lost when you run docker rm. Named volumes survive container removal and are managed by Docker — use docker volume ls to list them and docker volume inspect mysql-data to find the storage location. In Docker Compose, declare the volume under the top-level volumes: key and reference it in the service’s volumes: list (the example in the Docker Compose section above shows this pattern).

How do containers in Docker Compose connect to MySQL?

Containers in the same Compose project share a default network. Your application container connects to MySQL using the service name as the hostname — if your database service is named db, the connection string is host=db port=3306. You don’t need to expose ports between containers; port mapping (-p 3306:3306) is only needed for connections from the host machine. Use depends_on: condition: service_healthy with a healthcheck on the MySQL service to prevent the application from starting before MySQL is ready.

How do I run a SQL file against a running container?

Troubleshooting

See also