- Pin a release line:
mysql:8.4ormysql:9.7(both LTS). Thelatesttag of the mysql image now points to the 26.7 Innovation release. - For MariaDB, the
ltstag is 12.3 andlatestis 13.0. MariaDB usesMARIADB_*variables and themariadbandmariadb-dumpclient names. - Mount a volume at
/var/lib/mysqlfor both images. Environment variables and/docker-entrypoint-initdb.dfiles only apply to an empty data directory. - In Docker Compose, a healthcheck plus
depends_on: condition: service_healthystops Adminer, phpMyAdmin or your app from connecting before initialisation finishes. - Back up with
docker execandmysqldump(MySQL) ormariadb-dump(MariaDB); the MariaDB image no longer ships themysqldumpname.
Docker MySQL: pick a tag and start the server
Docker MySQL setups start from the mysql Docker Official Image, maintained by the Docker community and the MySQL team. Oracle now runs two LTS lines and an Innovation line, and the image tags follow them. LTS releases only receive fixes within a series; Innovation releases add features and behaviour changes and are supported until the next Innovation release. For a development database that should behave like production, pin the same LTS line your servers use.
docker run --name mysql -e MYSQL_ROOT_PASSWORD=<your-password> -p 3306:3306 -v mysqldata:/var/lib/mysql -d mysql:8.4docker exec -it mysql mysql -uroot -p| Tag | Version | Track |
|---|---|---|
mysql:8.4 (also 8) | 8.4.11 | LTS |
mysql:9.7 (also 9, lts) | 9.7.2 | LTS |
mysql:26.7 (also 26, innovation, latest) | 26.7.0 | Innovation |
Oracle's own MySQL images
The MySQL Reference Manual documents a separate set of images maintained by the MySQL team at the Oracle Container Registry, pulled as container-registry.oracle.com/mysql/community-server:tag. The manual states that these images are built for Linux platforms only and that other platforms are not supported. Most local setups, including Docker Desktop on Windows 11 and macOS, use the Docker Hub mysql image shown above.
MariaDB in Docker
The mariadb image documents latest as the latest stable version and lts as the last long-term support release. On 8 October 2026 that is 13.0.2 for latest and 12.3.3 for lts, with 11.8, 11.4, 10.11 and 10.6 also tagged. One of MARIADB_ROOT_PASSWORD, MARIADB_ROOT_PASSWORD_HASH, MARIADB_RANDOM_ROOT_PASSWORD or MARIADB_ALLOW_EMPTY_ROOT_PASSWORD is required.
Two image defaults differ from a package install: the configuration sets host-cache-size=0 and skip-name-resolve, which disables authentication of user@hostname accounts. Use IP or % host patterns for container accounts, or re-enable name resolution as the image documentation describes. Setting MARIADB_AUTO_UPGRADE runs mariadb-upgrade when you move an existing volume to a newer image, and keeps a backup of the system tables unless you disable it.
docker run --detach --name mariadb -p 3306:3306 -v mariadbdata:/var/lib/mysql --env MARIADB_ROOT_PASSWORD=<your-password> --env MARIADB_DATABASE=mydb --env MARIADB_USER=app --env MARIADB_PASSWORD=<app-password> mariadb:lts| Purpose | mysql image | mariadb image |
|---|---|---|
| Root password (required, or an alternative) | MYSQL_ROOT_PASSWORD | MARIADB_ROOT_PASSWORD |
| Database created on first start | MYSQL_DATABASE | MARIADB_DATABASE |
| Extra user with full rights on that database | MYSQL_USER, MYSQL_PASSWORD | MARIADB_USER, MARIADB_PASSWORD |
| Random root password printed to the log | MYSQL_RANDOM_ROOT_PASSWORD | MARIADB_RANDOM_ROOT_PASSWORD |
| Empty root password (not recommended) | MYSQL_ALLOW_EMPTY_PASSWORD | MARIADB_ALLOW_EMPTY_ROOT_PASSWORD |
| Read a value from a file (Docker secrets) | Append _FILE | Append _FILE |
| Command-line client in the image | mysql | mariadb |
Docker Compose: MySQL with Adminer or phpMyAdmin
The file below runs MySQL 8.4 with both web tools; keep whichever you prefer. It uses the current Compose Specification without the obsolete top-level version: key. The MySQL healthcheck uses mysqladmin ping, which the MySQL manual documents as returning 0 when the server is running, even if the connection is refused with Access denied, so no password is needed in the check.
services:
db:
image: mysql:8.4
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:?set MYSQL_ROOT_PASSWORD in .env}
MYSQL_DATABASE: mydb
MYSQL_USER: app
MYSQL_PASSWORD: ${MYSQL_PASSWORD:?set MYSQL_PASSWORD in .env}
ports:
- "127.0.0.1:3306:3306"
volumes:
- mysqldata:/var/lib/mysql
- ./initdb:/docker-entrypoint-initdb.d:ro
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
adminer:
image: adminer:6
restart: unless-stopped
environment:
ADMINER_DEFAULT_SERVER: db
ports:
- "8080:8080"
depends_on:
db:
condition: service_healthy
phpmyadmin:
image: phpmyadmin:5.2
restart: unless-stopped
environment:
PMA_HOST: db
ports:
- "8081:80"
depends_on:
db:
condition: service_healthy
volumes:
mysqldata:MYSQL_ROOT_PASSWORD=<your-root-password>
MYSQL_PASSWORD=<your-app-password> db:
image: mariadb:lts
restart: unless-stopped
environment:
MARIADB_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:?set MYSQL_ROOT_PASSWORD in .env}
MARIADB_DATABASE: mydb
MARIADB_USER: app
MARIADB_PASSWORD: ${MYSQL_PASSWORD:?set MYSQL_PASSWORD in .env}
volumes:
- mariadbdata:/var/lib/mysql
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
start_period: 10s
interval: 10s
timeout: 5s
retries: 3Start it and sign in
- Run
docker compose up -din the folder, thendocker compose psuntildbshows healthy. - Adminer: open
http://localhost:8080.ADMINER_DEFAULT_SERVERsets the default server todb; sign in asapporroot. - phpMyAdmin: open
http://localhost:8081.PMA_HOSTpoints it atdb, and it signs in with your MySQL credentials.
The Adminer image supports MySQL, PostgreSQL, SQLite, SimpleDB and Elasticsearch out of the box, so the same container can also manage the Postgres stack from the PostgreSQL in Docker guide. phpMyAdmin is for MySQL and MariaDB only. If you use the MariaDB variant, rename the volume in the top-level volumes: section to mariadbdata.
Loading init SQL and existing dumps
On the first start, both images run files found in /docker-entrypoint-initdb.d in alphabetical order: .sh, .sql, .sql.gz, .sql.xz and .sql.zst for both, plus .sql.bz2 for the mysql image. SQL files are imported into the database named by MYSQL_DATABASE (or MARIADB_DATABASE). That makes this folder the simplest way to seed a container from a dump: put 01-schema.sql and 02-data.sql.gz in ./initdb and start from an empty volume.
Nothing in the folder runs again once the volume contains a database. With an initialised volume the images also ignore the password and database variables; for the mysql image, MYSQL_ROOT_PASSWORD should be omitted in that case because it will be ignored anyway. To load a dump into an existing container, pipe it to the client instead, as shown in the backup section.
CREATE TABLE customers (
customer_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO customers (name) VALUES ('Ada'), ('Grace');Docker MySQL host: connecting from your machine and other containers
From the host. With -p 3306:3306, tools such as MySQL Workbench, DBeaver or the mysql client connect to host 127.0.0.1 on port 3306. The Compose file publishes the port as 127.0.0.1:3306:3306, which Docker documents as keeping the port local to the machine. If a local MySQL or MariaDB service already uses 3306, map another host port, such as 3307:3306.
From other containers. In Compose, every service joins a default network and is reachable by its service name, so the host name for the database is db, not localhost. With plain docker run, create a user-defined network and start both containers on it, then use the container name as the host. The mysql image documentation warns that setting a MYSQL_HOST variable is known to cause issues with the image, so set your application's own host variable instead.
Server options can be passed after the image name, for example mysql:8.4 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci, or placed in a .cnf file mounted at /etc/mysql/conf.d.
| Error | Usual cause | What to check |
|---|---|---|
ERROR 2003: Can't connect to MySQL server | Port not published, wrong host port, or the server is still initialising | docker compose ps, the ports mapping, and the docker logs output |
ERROR 1045 (28000): Access denied for user | Wrong password, or the volume was initialised earlier with different credentials | Credentials in the existing volume win over changed environment variables |
App container cannot reach localhost:3306 | Inside a container, localhost is the container itself | Use the service name (db) as the host |
Connection refused right after docker compose up | No connections are accepted until initialisation completes | Add a healthcheck and condition: service_healthy |
Backing up and restoring a MySQL or MariaDB container
The image documentation recommends running the dump tool inside the container with docker exec, so it can reach the server without extra networking. Note the single quotes: the password variable is expanded inside the container, not on your host.
docker exec mysql sh -c 'exec mysqldump --all-databases -uroot -p"$MYSQL_ROOT_PASSWORD"' > all-databases.sqldocker exec -i mysql sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD"' < all-databases.sqldocker exec mariadb sh -c 'mariadb-dump --all-databases -u root -p"$MARIADB_ROOT_PASSWORD" > backup/db.sql'Notes for Windows and MariaDB
In PowerShell, < cannot be used for input redirection, so run the restore line from cmd or Git Bash, or copy the file into the container with docker cp first. The MariaDB example assumes a volume mounted at /backup as in MariaDB's container backup documentation. From MariaDB 11.0 the mysqldump name is deprecated and removed from the mariadb image, so scripts must call mariadb-dump. For physical backups, the image also includes mariadb-backup.
Options for consistent dumps (--single-transaction, --routines, --events), restoring to another server and scheduling are covered in the mysqldump guide listed under related pages.
Frequently asked questions
Which docker hub mysql tag should I use?
Pin the LTS line that matches your servers: mysql:8.4 or mysql:9.7. Avoid latest for anything you keep, because on 8 October 2026 it points to the 26.7 Innovation release, and Innovation releases can change behaviour between versions.
Is Adminer in Docker safe to expose?
Treat Adminer and phpMyAdmin as local development tools. Both give full database access to anyone who can reach the port and sign in, so publish them on 127.0.0.1 or keep them off servers reachable from the internet.
What is the difference between the mysql and mariadb images?
They run different servers. The mysql image runs Oracle's MySQL and uses MYSQL_* variables; the mariadb image runs MariaDB Server, uses MARIADB_* variables and names its tools mariadb, mariadb-dump and mariadb-backup. Both store data in /var/lib/mysql. See MariaDB vs MySQL for how the servers differ.
Why is my docker mysql database empty after restarting?
If no volume or bind mount is attached at /var/lib/mysql, the data lives in an anonymous volume tied to that container; re-creating the container starts a new, empty one. Use a named volume as in the examples above and avoid docker compose down -v, which deletes named volumes.
How do I change the MySQL root password in Docker?
Changing MYSQL_ROOT_PASSWORD has no effect once the volume holds a database. Connect with the current password and change it with SQL; MariaDB documents a separate procedure for resetting lost passwords in its Docker Official Image FAQ.
Sources
- mysql Docker Official Image documentation (docker-library/docs)
- mariadb Docker Official Image documentation (docker-library/docs)
- adminer Docker Official Image documentation (docker-library/docs)
- phpmyadmin Docker Official Image documentation (docker-library/docs)
- MySQL Community Server downloads
- MySQL 8.4 Reference Manual: MySQL Releases, Innovation and LTS
- MySQL 8.4 Reference Manual: Basic Steps for MySQL Server Deployment with Docker
- MySQL 8.4 Reference Manual: mysqladmin
- MySQL 8.4 Reference Manual: Troubleshooting problems connecting to MySQL
- MariaDB documentation: Using Healthcheck.sh
- MariaDB documentation: Container Backup and Restoration
- MariaDB documentation: mariadb-dump
- Docker docs: Control startup order in Compose
- Docker docs: Compose version and name elements
- Docker docs: Networking in Compose
- Docker docs: Publishing and exposing ports
- MySQL 8.4 Reference Manual: Reloading SQL-Format Backups
Checked 8 October 2026.
How we research guides: our editorial method. We link only to official downloads and never host installers.