Conteúdo
MySQL com Docker: tutorial para instalar, conectar, fazer backup e restaurar
Inicie com um único comando
Primeiro, prepare uma pasta mysql-demo e coloque nela dois arquivos SQL de inicialização (explicados adiante) dentro de initdb/:
mysql-demo/
└── initdb/
├── 01-schema.sql
└── 02-seed.sql
initdb/01-schema.sql:
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price INT NOT NULL
);
initdb/02-seed.sql:
INSERT INTO products (name, price) VALUES ('珍珠奶茶', 65), ('鳳梨酥', 45), ('牛肉麵', 180);
Inicie o MySQL na pasta mysql-demo:
docker run -d --name mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=app \
-e MYSQL_USER=app \
-e MYSQL_PASSWORD=apppass \
-p 127.0.0.1:3306:3306 \
-v mysql_data:/var/lib/mysql \
-v "$(pwd)/initdb:/docker-entrypoint-initdb.d:ro" \
--restart unless-stopped \
mysql:8.4
docker run -d --name mysql `
-e MYSQL_ROOT_PASSWORD=secret `
-e MYSQL_DATABASE=app `
-e MYSQL_USER=app `
-e MYSQL_PASSWORD=apppass `
-p 127.0.0.1:3306:3306 `
-v mysql_data:/var/lib/mysql `
-v "${PWD}/initdb:/docker-entrypoint-initdb.d:ro" `
--restart unless-stopped `
mysql:8.4
docker run -d --name mysql ^
-e MYSQL_ROOT_PASSWORD=secret ^
-e MYSQL_DATABASE=app ^
-e MYSQL_USER=app ^
-e MYSQL_PASSWORD=apppass ^
-p 127.0.0.1:3306:3306 ^
-v mysql_data:/var/lib/mysql ^
-v "%cd%/initdb:/docker-entrypoint-initdb.d:ro" ^
--restart unless-stopped ^
mysql:8.4
$ docker run -d --name mysql -e MYSQL_ROOT_PASSWORD=secret -e MYSQL_DATABASE=app -e MYSQL_USER=app -e MYSQL_PASSWORD=apppass -p 127.0.0.1:3306:3306 -v mysql_data:/var/lib/mysql -v "$(pwd)/initdb:/docker-entrypoint-initdb.d:ro" --restart unless-stopped mysql:8.4
Unable to find image 'mysql:8.4' locally
8.4: Pulling from library/mysql
e896da32f635: Pull complete
3527249a8025: Pull complete
6b54d15c954d: Pull complete
15ba404f5528: Pull complete
ad73434ffdad: Pull complete
bf11ec3e7e56: Pull complete
81077ec0e5ac: Pull complete
f51a9a1f0d20: Pull complete
4ba189089539: Pull complete
d4cc7515d7b7: Pull complete
Digest: sha256:24989179f58856db763f418010c1169fecc944e3ec1ea7e921572d83eb070f70
Status: Downloaded newer image for mysql:8.4
d92a7561ad58f958488c606bb07753aeffcc06639878a4c87ed676f6e1f99389
Forma correspondente para Windows (selecione uma aba para alternar):
docker run -d --name mysql -e MYSQL_ROOT_PASSWORD=secret -e MYSQL_DATABASE=app -e MYSQL_USER=app -e MYSQL_PASSWORD=apppass -p 127.0.0.1:3306:3306 -v mysql_data:/var/lib/mysql -v "$(pwd)/initdb:/docker-entrypoint-initdb.d:ro" --restart unless-stopped mysql:8.4
docker run -d --name mysql -e MYSQL_ROOT_PASSWORD=secret -e MYSQL_DATABASE=app -e MYSQL_USER=app -e MYSQL_PASSWORD=apppass -p 127.0.0.1:3306:3306 -v mysql_data:/var/lib/mysql -v "${PWD}/initdb:/docker-entrypoint-initdb.d:ro" --restart unless-stopped mysql:8.4
docker run -d --name mysql -e MYSQL_ROOT_PASSWORD=secret -e MYSQL_DATABASE=app -e MYSQL_USER=app -e MYSQL_PASSWORD=apppass -p 127.0.0.1:3306:3306 -v mysql_data:/var/lib/mysql -v "%cd%/initdb:/docker-entrypoint-initdb.d:ro" --restart unless-stopped mysql:8.4
| Parâmetro | Descrição |
|---|---|
MYSQL_ROOT_PASSWORD | Senha do root (obrigatória; como alternativa, use MYSQL_RANDOM_ROOT_PASSWORD=yes para gerar uma senha aleatória) |
MYSQL_DATABASE | Banco de dados criado na primeira inicialização |
MYSQL_USER / MYSQL_PASSWORD | Cria um usuário comum e concede a ele todas as permissões em MYSQL_DATABASE |
-p 127.0.0.1:3306:3306 | Disponibiliza apenas localmente; não é acessível de fora |
-v mysql_data:/var/lib/mysql | Os dados ficam no Volume chamado mysql_data |
-v .../initdb:/docker-entrypoint-initdb.d:ro | SQL executado durante a inicialização |
O que acontece na primeira inicialização
$ docker logs mysql 2>&1 | grep -E "Entrypoint|initdb|ready for connections"
2026-10-13 00:46:59+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.4.11-1.el9 started.
2026-10-13 00:46:59+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2026-10-13 00:46:59+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.4.11-1.el9 started.
2026-10-13 00:46:59+00:00 [Note] [Entrypoint]: Initializing database files
2026-10-13 00:47:02+00:00 [Note] [Entrypoint]: Database files initialized
2026-10-13 00:47:02+00:00 [Note] [Entrypoint]: Starting temporary server
2026-10-13T00:47:04.184489Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Socket: /var/run/mysqld/mysqlx.sock
2026-10-13T00:47:04.185012Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.4.11' socket: '/var/run/mysqld/mysqld.sock' port: 0 MySQL Community Server - GPL.
2026-10-13 00:47:04+00:00 [Note] [Entrypoint]: Temporary server started.
2026-10-13 00:47:06+00:00 [Note] [Entrypoint]: Creating database app
2026-10-13 00:47:06+00:00 [Note] [Entrypoint]: Creating user app
2026-10-13 00:47:06+00:00 [Note] [Entrypoint]: Giving user app access to schema app
2026-10-13 00:47:06+00:00 [Note] [Entrypoint]: /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/01-schema.sql
2026-10-13 00:47:06+00:00 [Note] [Entrypoint]: /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/02-seed.sql
2026-10-13 00:47:06+00:00 [Note] [Entrypoint]: Stopping temporary server
2026-10-13 00:47:07+00:00 [Note] [Entrypoint]: Temporary server stopped
2026-10-13 00:47:07+00:00 [Note] [Entrypoint]: MySQL init process done. Ready for start up.
2026-10-13T00:47:08.596982Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
2026-10-13T00:47:08.597330Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.4.11' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server - GPL.
Pelos logs, o script de inicialização da imagem, na primeira inicialização (quando a pasta de dados está vazia), executa estas etapas:
- Cria os arquivos do banco de dados (
Initializing database files). - Inicia um servidor temporário (
Starting temporary server). Observeport: 0: o servidor temporário não aceita conexões de rede; só é possível conectar por socket. - Cria o banco de dados
app, o usuárioappe concede as permissões. - Executa os arquivos
01-schema.sqle02-seed.sqlde/docker-entrypoint-initdb.d/, em ordem alfabética. - Para o servidor temporário e inicia o servidor com a configuração final. Só o
port: 3306da última linha indica que já é possível conectar.
Todo o processo leva cerca de 10 segundos. /docker-entrypoint-initdb.d/ aceita arquivos .sql, .sql.gz e .sh, e só é executado na inicialização inicial. Reiniciar o contêiner depois disso não executa os arquivos novamente.
Escolha da versão
| tag | Descrição |
|---|---|
mysql:8.4 | Versão com suporte de longo prazo (LTS), recomendada para produção |
mysql:9 | Versão de inovação, com recursos mais novos e período de suporte mais curto |
mariadb:11 | MariaDB, uma ramificação altamente compatível com MySQL; as variáveis de ambiente passam a começar com MARIADB_ |
Conexão
De dentro do contêiner
O cliente mysql já está dentro do contêiner. Para uma sessão interativa, execute docker exec -it mysql mysql -uapp -p, digite a senha e acesse o prompt mysql>. Você também pode executar SQL diretamente com -e:
$ docker exec mysql mysql -uapp -papppass app -t -e "SELECT * FROM products;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+--------------+-------+
| id | name | price |
+----+--------------+-------+
| 1 | 珍珠奶茶 | 65 |
| 2 | 鳳梨酥 | 45 |
| 3 | 牛肉麵 | 180 |
+----+--------------+-------+
$ docker exec mysql mysql -uroot -psecret -t -e "SELECT VERSION(), @@character_set_server, @@collation_server;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----------+------------------------+--------------------+
| VERSION() | @@character_set_server | @@collation_server |
+-----------+------------------------+--------------------+
| 8.4.11 | utf8mb4 | utf8mb4_0900_ai_ci |
+-----------+------------------------+--------------------+
-texibe a saída em formato de tabela (sem modo interativo, o padrão é separar por tabulações).- Os dados em chinês são armazenados e lidos corretamente. O conjunto de caracteres do servidor é
utf8mb4e a regra de ordenação éutf8mb4_0900_ai_ci, valores padrão do MySQL 8 que não precisam de configuração adicional. As bordas das linhas com caracteres chineses não ficam alinhadas porque o clientemysqlcalcula a largura desses caracteres dessa forma; os dados não têm problema. - O aviso
[Warning] Using a password on the command line interface can be insecure.que aparece sempre lembra que outras pessoas podem ver a senha escrita no comando na lista de processos. Você pode ignorá-lo durante a demonstração.
Do host: diferença entre localhost e 127.0.0.1
No host, use qualquer cliente MySQL (MySQL Workbench, DBeaver ou o comando mysql) para conectar a 127.0.0.1:3306. Especifique 127.0.0.1 em vez de localhost. Use um contêiner com --network host para simular o cliente mysql no host e testar:
$ docker run --rm --network host mysql:8.4 mysql -h localhost -uapp -papppass -e "SELECT 1"
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)
$ docker run --rm --network host mysql:8.4 mysql -h 127.0.0.1 -uapp -papppass -e "SELECT USER(), CURRENT_USER()"
mysql: [Warning] Using a password on the command line interface can be insecure.
USER() CURRENT_USER()
app@172.18.0.1 app@%
-h localhost: falha comCan't connect to local MySQL server through socket. Quando o cliente MySQL recebelocalhost, ele usa um arquivo de socket Unix em vez de TCP. Esse arquivo de socket não existe no host (ele está dentro do contêiner).-h 127.0.0.1: funciona, usando TCP pela porta mapeada com-p.USER()mostraapp@172.18.0.1: do ponto de vista do MySQL, a conexão vem do IP do gateway da rede Docker, não de127.0.0.1.app@%emCURRENT_USER()indica que essa conta pode se conectar de qualquer host.
De outros contêineres
Coloque o MySQL e o aplicativo na mesma rede personalizada para conectar pelo nome do contêiner (a rede bridge padrão não resolve nomes. Consulte Conexão entre redes e contêineres):
$ docker network create appnet
595dfaad48e7460c5996b90a62402e50e31fb790a1f04b3cdc67ac12be482db6
$ docker network connect appnet mysql
$ docker run --rm --network appnet mysql:8.4 mysql -h mysql -uapp -papppass app -e "SELECT COUNT(*) FROM products"
mysql: [Warning] Using a password on the command line interface can be insecure.
COUNT(*)
3
A string de conexão do aplicativo fica assim:
mysql://app:apppass@mysql:3306/app
O nome do host é o nome do contêiner mysql (no Compose, é o nome do serviço), e a porta é 3306 dentro do contêiner. Não é necessário usar -p para conexões entre contêineres.
Gerencie com Compose
Em projetos reais, é recomendável usar Compose. Adicione compose.yaml, .env e o arquivo de configuração personalizado my.cnf a mysql-demo:
mysql-demo/
├── compose.yaml
├── .env
├── my.cnf
└── initdb/
├── 01-schema.sql
└── 02-seed.sql
.env:
MYSQL_ROOT_PASSWORD=change-this-root-password
MYSQL_PASSWORD=change-this-app-password
my.cnf:
[mysqld]
max_connections = 300
innodb_buffer_pool_size = 256M
compose.yaml:
services:
db:
image: mysql:8.4
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: app
MYSQL_USER: app
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
TZ: Asia/Taipei
ports:
- "127.0.0.1:3306:3306"
volumes:
- db_data:/var/lib/mysql
- ./initdb:/docker-entrypoint-initdb.d:ro
- ./my.cnf:/etc/mysql/conf.d/custom.cnf:ro
healthcheck:
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -uroot -p\"$$MYSQL_ROOT_PASSWORD\" --silent"]
interval: 10s
retries: 10
start_period: 30s
restart: unless-stopped
volumes:
db_data:
| Configuração | Descrição |
|---|---|
TZ: Asia/Taipei | Define o fuso horário do contêiner; o NOW() do MySQL usará esse fuso horário |
./my.cnf:/etc/mysql/conf.d/custom.cnf | O MySQL lê os arquivos .cnf em /etc/mysql/conf.d/ |
$$MYSQL_ROOT_PASSWORD | $$ impede que o Compose substitua a variável; ela fica para o shell dentro do contêiner ler a variável de ambiente do contêiner |
-h 127.0.0.1 | Importante, veja a explicação abaixo |
$ docker compose up -d --wait
[+] up 3/3
✔ Network mysql-demo_default Created 0.0s
✔ Volume mysql-demo_db_data Created 0.0s
✔ Container mysql-demo-db-1 Healthy 10.9s
$ docker compose exec db sh -c 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "SELECT 1"'
mysql: [Warning] Using a password on the command line interface can be insecure.
1
1
$ docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
mysql-demo-db-1 mysql:8.4 "docker-entrypoint.s…" db 12 seconds ago Up 11 seconds (healthy) 127.0.0.1:3306->3306/tcp, 33060/tcp
$ docker compose exec db sh -c 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -t -e "SELECT @@max_connections, @@innodb_buffer_pool_size DIV 1048576 AS buffer_pool_mb, @@system_time_zone, NOW();"'
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------------+----------------+--------------------+---------------------+
| @@max_connections | buffer_pool_mb | @@system_time_zone | NOW() |
+-------------------+----------------+--------------------+---------------------+
| 300 | 256 | CST | 2026-10-13 08:49:41 |
+-------------------+----------------+--------------------+---------------------+
$ docker compose exec db sh -c 'mysql -uapp -p"$MYSQL_PASSWORD" app -t -e "SELECT * FROM products"'
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+--------------+-------+
| id | name | price |
+----+--------------+-------+
| 1 | 珍珠奶茶 | 65 |
| 2 | 鳳梨酥 | 45 |
| 3 | 牛肉麵 | 180 |
+----+--------------+-------+
--waitaguarda o serviço ficar healthy antes de retornar. Foram cerca de 11 segundos atéHealthy, em linha com o tempo de inicialização visto antes.max_connectionsé 300 ebuffer_pool_mbé 256;my.cnffoi aplicado.@@system_time_zoneéCST(China Standard Time, UTC+8), eNOW()mostra o horário de Taipei.- O SQL de inicialização também foi executado; há três registros em
products.
Armadilha na verificação de integridade: localhost informa healthy cedo demais
Uma forma comum de verificar a integridade do MySQL na internet é mysqladmin ping -h localhost. Testamos trocando o 127.0.0.1 acima por localhost:
$ docker compose up -d --wait
[+] up 3/3
✔ Network mysql-demo_default Created 0.0s
✔ Volume mysql-demo_db_data Created 0.0s
✔ Container mysql-demo-db-1 Healthy 5.8s
$ docker compose exec db sh -c 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "SELECT 1"'
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
$ docker compose logs db 2>&1 | grep -E "Temporary server|init process done|port: 3306"
db-1 | 2026-10-13 08:49:02+08:00 [Note] [Entrypoint]: Temporary server started.
$ docker compose exec db sh -c 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "SELECT 1"'
mysql: [Warning] Using a password on the command line interface can be insecure.
1
1
- Após apenas 5.8 segundos, o serviço informa
Healthy, mas logo em seguida a conexão com root falha. O log mostra que o processo ainda estava emTemporary server started. - Só funcionou quando tentamos de novo 10 segundos depois.
O motivo é que o servidor temporário durante a inicialização só aceita conexões por socket, e -h localhost usa justamente o socket. Por isso, o ping recebe uma resposta. Além disso, mysqladmin ping considera bem-sucedido sempre que o servidor responde, mesmo que ainda não seja possível entrar com usuário e senha. Assim, o Compose acredita que o banco de dados já está pronto e inicia os serviços que dependem dele (depends_on com condition: service_healthy); na primeira conexão, o aplicativo pode falhar.
Com -h 127.0.0.1, a conexão usa TCP. O servidor temporário não aceita conexões de rede (port: 0), então o serviço só informa healthy depois que o servidor definitivo inicia.
Backup e restauração
Exporte o SQL com mysqldump, exclua uma tabela de propósito e depois restaure-a a partir do backup:
$ docker exec mysql sh -c 'mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" --single-transaction app' > app.sql
mysqldump: [Warning] Using a password on the command line interface can be insecure.
$ ls -lh app.sql && grep -c "INSERT INTO" app.sql
-rw-r--r-- 1 root root 2.0K Oct 13 00:47 app.sql
1
$ docker exec mysql mysql -uroot -psecret -e "DROP TABLE app.products"
mysql: [Warning] Using a password on the command line interface can be insecure.
$ docker exec mysql mysql -uapp -papppass app -e "SELECT COUNT(*) FROM products"
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1146 (42S02) at line 1: Table 'app.products' doesn't exist
$ docker exec -i mysql sh -c 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" app' < app.sql
mysql: [Warning] Using a password on the command line interface can be insecure.
$ docker exec mysql mysql -uapp -papppass app -t -e "SELECT * FROM products"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+--------------+-------+
| id | name | price |
+----+--------------+-------+
| 1 | 珍珠奶茶 | 65 |
| 2 | 鳳梨酥 | 45 |
| 3 | 牛肉麵 | 180 |
+----+--------------+-------+
- O comando de backup é envolvido por
sh -c '...', e$MYSQL_ROOT_PASSWORDé expandido dentro do contêiner. Assim, a senha não aparece no histórico de comandos do host. As aspas simples externas impedem que o shell do host substitua a variável primeiro. --single-transactionexporta as tabelas InnoDB em um snapshot consistente, sem bloqueá-las durante o backup. Em produção, sempre inclua essa opção.- O arquivo de backup
app.sqltem 2.0K e contém 1 comandoINSERT INTO(os três registros são gravados em um único INSERT). - Depois de
DROP TABLE, a consulta retornaTable 'app.products' doesn't exist. - Para restaurar, use
docker exec -ie envieapp.sql, que está no host, aomysqldentro do contêiner pela entrada padrão. Os dados são restaurados por completo.
Na restauração, use apenas -i, não -it. Quando a entrada padrão é um arquivo, e não um terminal, -t causa um erro:
$ docker exec -it mysql sh -c "echo hi" < /dev/null
cannot attach stdin to a TTY-enabled container because stdin is not a terminal
Outros comandos de backup comuns:
# Fazer backup de todos os bancos de dados (incluindo usuários e permissões)
docker exec mysql sh -c 'mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" --all-databases --single-transaction' > all.sql
# Fazer backup e compactar
docker exec mysql sh -c 'mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" --single-transaction app' | gzip > app.sql.gz
# Restaurar um backup compactado
gunzip < app.sql.gz | docker exec -i mysql sh -c 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" app'
Backup e restauração para usuários do Windows
O PowerShell não oferece suporte a <, e o > do Windows PowerShell 5.1 salva os arquivos com codificação UTF-16, causando erros na importação. Em vez disso, gere o arquivo dentro do contêiner e depois copie-o com docker cp. Esse método funciona em todos os sistemas:
# Backup: exporte para /tmp/app.sql dentro do contêiner e copie o arquivo para fora
docker exec mysql sh -c 'mysqldump -uroot -p$MYSQL_ROOT_PASSWORD --single-transaction --result-file=/tmp/app.sql app'
docker cp mysql:/tmp/app.sql app.sql
# Restauração: copie o arquivo para dentro e importe-o no contêiner
docker cp app.sql mysql:/tmp/restore.sql
docker exec mysql sh -c 'mysql -uroot -p$MYSQL_ROOT_PASSWORD app < /tmp/restore.sql'
# Backup: exporte para /tmp/app.sql dentro do contêiner e copie o arquivo para fora
docker exec mysql sh -c 'mysqldump -uroot -p$MYSQL_ROOT_PASSWORD --single-transaction --result-file=/tmp/app.sql app'
docker cp mysql:/tmp/app.sql app.sql
# Restauração: copie o arquivo para dentro e importe-o no contêiner
docker cp app.sql mysql:/tmp/restore.sql
docker exec mysql sh -c 'mysql -uroot -p$MYSQL_ROOT_PASSWORD app < /tmp/restore.sql'
REM Backup: exporte para /tmp/app.sql dentro do contêiner e copie o arquivo para fora
docker exec mysql sh -c "mysqldump -uroot -p$MYSQL_ROOT_PASSWORD --single-transaction --result-file=/tmp/app.sql app"
docker cp mysql:/tmp/app.sql app.sql
REM Restauração: copie o arquivo para dentro e importe-o no contêiner
docker cp app.sql mysql:/tmp/restore.sql
docker exec mysql sh -c "mysql -uroot -p$MYSQL_ROOT_PASSWORD app < /tmp/restore.sql"
--result-filefaz com que mysqldump grave diretamente no arquivo, sem redirecionamento pelo terminal.- O
<do comando fica dentro da string desh -ce é processado pelo shell dentro do contêiner. Por isso, o comando também funciona no PowerShell. - Não coloque aspas em
-p$MYSQL_ROOT_PASSWORDpara evitar problemas com aspas internas no PowerShell 5.1 (a senha não deve conter espaços).
Este conjunto de comandos foi testado no Docker 29 e restaurou os 3 registros por completo:
$ docker exec mysql sh -c 'mysql -uroot -p$MYSQL_ROOT_PASSWORD app -e "CREATE TABLE t (id INT); INSERT INTO t VALUES (1),(2),(3);"'
mysql: [Warning] Using a password on the command line interface can be insecure.
$ docker exec mysql sh -c 'mysqldump -uroot -p$MYSQL_ROOT_PASSWORD --single-transaction --result-file=/tmp/app.sql app'
mysqldump: [Warning] Using a password on the command line interface can be insecure.
$ docker cp mysql:/tmp/app.sql app.sql
$ ls -l app.sql
-rw-rw-rw- 1 root root 1788 Oct 14 09:48 app.sql
$ docker exec mysql sh -c 'mysql -uroot -p$MYSQL_ROOT_PASSWORD app -e "DROP TABLE t"'
mysql: [Warning] Using a password on the command line interface can be insecure.
$ docker cp app.sql mysql:/tmp/restore.sql
$ docker exec mysql sh -c 'mysql -uroot -p$MYSQL_ROOT_PASSWORD app < /tmp/restore.sql'
mysql: [Warning] Using a password on the command line interface can be insecure.
$ docker exec mysql sh -c 'mysql -uroot -p$MYSQL_ROOT_PASSWORD app -e "SELECT COUNT(*) FROM t"'
mysql: [Warning] Using a password on the command line interface can be insecure.
COUNT(*)
3
Teste prático: alterei a variável de senha, mas não funcionou
Variáveis como MYSQL_ROOT_PASSWORD são usadas somente na primeira inicialização (quando o Volume está vazio). Remova o contêiner, mantenha o Volume e crie o contêiner novamente com outra senha:
$ docker rm -f mysql
mysql
$ docker run -d --name mysql -e MYSQL_ROOT_PASSWORD=different -v mysql_data:/var/lib/mysql mysql:8.4
2a0f52d379b574033ae1571ab6873f37e8ab79ccd3830f6feac629696b74ae42
$ docker logs mysql 2>&1 | grep -c "Initializing database"
0
$ docker exec mysql mysql -uroot -pdifferent -e "SELECT 1"
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
$ docker exec mysql mysql -uroot -psecret -e "SELECT 1"
mysql: [Warning] Using a password on the command line interface can be insecure.
1
1
Initializing databaseaparece 0 vezes nos logs: o Volume já contém dados, então o script de inicialização foi ignorado.- Não é possível entrar com a nova senha
different; a senha antigasecretainda funciona.
Isso significa que, depois que os dados existem, alterar MYSQL_ROOT_PASSWORD não tem efeito. Para alterar a senha, entre com a senha antiga e execute o SQL:
ALTER USER 'root'@'%' IDENTIFIED BY 'NovaSenha';
ALTER USER 'root'@'localhost' IDENTIFIED BY 'NovaSenha';
Ou, se não precisar manter os dados, remova o Volume e inicialize novamente (docker compose down -v; todos os dados serão perdidos).
Solução de problemas
Access denied for user 'root'@'...'
$ docker exec mysql mysql -uroot -pwrong -e "SELECT 1"
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
- A senha está incorreta ou o Volume foi inicializado com uma senha antiga (veja o teste prático acima).
- Por padrão, root tem duas contas,
root@%eroot@localhost, que permitem conexões de qualquer host. Para usuários criados por você, confirme se o host é%; caso contrário, eles só poderão se conectar de um host específico.
Can't connect to local MySQL server through socket
O cliente trata localhost como uma conexão por socket. Use 127.0.0.1 (veja o teste prático anterior).
O contêiner encerra logo após iniciar
Veja os logs: docker logs mysql. Causas comuns:
MYSQL_ROOT_PASSWORDnão foi definida (e nemMYSQL_ALLOW_EMPTY_PASSWORDouMYSQL_RANDOM_ROOT_PASSWORD).- O Volume contém dados inicializados por outra versão (por exemplo, 5.7 ou MariaDB), incompatíveis com a versão atual.
- Falta memória no host.
Atualização da versão 5.7 / 8.0
Não monte diretamente um Volume antigo na imagem de uma versão mais nova. Primeiro, exporte os dados com mysqldump, importe-os em um banco de dados vazio da nova versão e valide tudo em um ambiente de teste.
Resumo
- Coloque o SQL de inicialização em
/docker-entrypoint-initdb.d/; ele é executado somente na primeira inicialização. - Para se conectar pelo host, use
127.0.0.1;localhostusa uma conexão por socket. - Configure a verificação de integridade com
mysqladmin ping -h 127.0.0.1. - Faça backups com
mysqldump --single-transactione teste a restauração.
Exercícios
Exercício 1: liste todos os bancos de dados no contêiner MySQL com um único comando.
Resposta
docker exec mysql sh -c 'mysql -uroot -p$MYSQL_ROOT_PASSWORD -e "SHOW DATABASES"'
Exercício 2: a configuração do MySQL no Compose define ports: "127.0.0.1:3306:3306". Qual nome de host e porta um aplicativo no mesmo projeto Compose deve usar para se conectar?
Resposta
O nome do host é o nome do serviço db, e a porta é 3306, dentro do contêiner. ports afeta somente as conexões feitas pelo host; os contêineres não precisam dessa configuração para se conectar entre si.
Perguntas frequentes
O texto em chinês aparece corrompido?
No MySQL 8, o padrão já é utf8mb4. A corrupção geralmente vem do conjunto de caracteres da conexão do cliente ou da codificação do arquivo importado; no Windows PowerShell 5.1, um backup salvo com > fica em UTF-16. Use a forma com docker cp mostrada neste capítulo.
Devo usar MySQL ou MariaDB?
Os dois são altamente compatíveis. Programas comuns, como o WordPress, oferecem suporte a ambos; no MariaDB, as variáveis de ambiente começam com MARIADB_.
A alteração de MYSQL_ROOT_PASSWORD não teve efeito?
A variável de senha só é usada quando o Volume está vazio. Depois disso, altere a senha com SQL. Veja o teste prático neste capítulo.
Atualizado 14 de outubro de 2026