Access denied (authentication failure) no MySQL: causas reais e roteiro de diagnóstico
- Siltech Consult
- há 1 dia
- 4 min de leitura
O sintoma
ERROR 1045 (28000): Access denied for user 'app_user'@'10.0.x.x' (using password: YES) é um dos erros mais reportados no MySQL, e também um dos mais mal diagnosticados. A mensagem é genérica por natureza: ela dispara para credencial incorreta, para usuário que não existe para aquele host específico e para incompatibilidade de plugin de autenticação — três causas com correções completamente diferentes. Tratar todos os casos como "senha errada" e sair trocando senha é o motivo pelo qual esse erro volta a aparecer dias depois.
Este post é um roteiro de diagnóstico para ir da mensagem genérica até a causa real, sem achismo.
Diagnóstico passo a passo
1. Confirme se o usuário existe para aquele host exato
O MySQL não trata user como uma entidade única — a chave real é o par user@host. É comum existir app_user@10.0.1.5 mas a aplicação estar conectando de 10.0.1.6, ou existir app_user@localhost quando a conexão chega via TCP/IP e precisaria de app_user@10.0.% ou app_user@%.
SELECT user, host, plugin, account_locked
FROM mysql.user
WHERE user = 'app_user';
Se a linha esperada não aparecer com o host correto, a causa já está identificada: falta de entrada para aquele host, não senha incorreta.
2. Lembre-se de como o MySQL resolve qual linha usar
Quando existe mais de uma linha para o mesmo usuário com hosts diferentes (por exemplo app_user@10.0.1.5 e app_user@%), o servidor ordena as linhas com os valores de Host mais específicos primeiro e usa a primeira que casar com a conexão — não necessariamente a que você "esperava" que fosse usada. Um detalhe frequentemente esquecido: uma linha de usuário anônimo (User em branco) com host mais específico pode ser escolhida antes de uma linha nomeada com host menos específico. Isso é comportamento documentado da Oracle para a fase de "Connection Verification" do controle de acesso, não bug.
3. Verifique incompatibilidade de plugin de autenticação
Desde o MySQL 8.0.4, o plugin de autenticação padrão passou de mysql_native_password para caching_sha2_password. A partir do MySQL 8.4, mysql_native_password está deprecated, ou seja, troque o quanto antes de sua aplicação. Esse é hoje um dos motivos mais comuns de Access denied em ambientes que foram migrados ou tiveram o servidor atualizado: o driver/cliente da aplicação (versões antigas de conectores Java, PHP, Python) não suporta caching_sha2_password e a autenticação falha mesmo com a senha certa.
SELECT user, host, plugin
FROM mysql.user
WHERE user = 'app_user';
Se o plugin estiver como caching_sha2_password e o cliente for antigo ou não suportar o protocolo, a solução é recriar a credencial com o plugin compatível:
ALTER USER 'app_user'@'10.0.%' IDENTIFIED WITH mysql_native_password BY 'senha_atual';
(Avalie o trade-off de segurança antes de reverter para mysql_native_password — é uma correção de compatibilidade, não a opção recomendada por padrão pela própria Oracle.)
4. Confira o error log para a mensagem completa
O ERROR 1045 que chega ao cliente é resumido. O log de erros do servidor registra mais contexto sobre tentativas de conexão rejeitadas quando log_error_verbosity está no valor padrão (3):
SHOW VARIABLES LIKE 'log_error_verbosity';
Com verbosity 3 (padrão), o servidor já registra conexões abortadas e erros de acesso negado no log de erros — vale checar esse arquivo antes de qualquer alteração de configuração, em vez de assumir que é preciso mudar o parâmetro.
5. Confirme os privilégios, não só a autenticação
Um erro comum é resolver a autenticação e continuar vendo comportamento de acesso negado em operações específicas — nesse caso o problema já não é mais o 1045, e sim falta de GRANT:
SHOW GRANTS FOR 'app_user'@'10.0.%';
Solução aplicada
Combinando os passos acima, a correção cai em um destes três cenários. Se o host estava errado, crie a entrada correta com CREATE USER 'app_user'@'10.0.%' IDENTIFIED BY '...' e replique os GRANT da entrada existente. Se o plugin era incompatível, use ALTER USER para ajustar o plugin de autenticação, ou atualize o driver/conector cliente para suportar caching_sha2_password. E se a senha estava mesmo incorreta, redefina com ALTER USER 'app_user'@'10.0.%' IDENTIFIED BY 'nova_senha';.
Um ponto técnico que gera confusão: FLUSH PRIVILEGES não é necessário após CREATE USER, ALTER USER, GRANT ou REVOKE — esses comandos já atualizam as tabelas de privilégio em memória. FLUSH PRIVILEGES só é exigido quando as tabelas de grant (mysql.user, mysql.db etc.) são alteradas diretamente via INSERT/UPDATE/DELETE, o que deve ser evitado.
Quando o acesso está totalmente bloqueado
Se o usuário afetado for o próprio root e não houver outra conta com privilégio de administração disponível, a recuperação documentada pela Oracle é subir a instância com --skip-grant-tables (que ativa automaticamente --skip-networking, bloqueando conexões remotas por segurança), conectar localmente sem senha, redefinir a credencial com ALTER USER e reiniciar o serviço normalmente. É um procedimento que exige acesso ao host e parada do serviço — não é algo a se fazer em produção sem janela de manutenção.
Validação
Depois da correção, valide a partir do mesmo host/rede de onde a aplicação se conecta de fato — não apenas do host do DBA:
SELECT user, host, plugin FROM mysql.user WHERE user = 'app_user';
SHOW GRANTS FOR 'app_user'@'10.0.%';
E teste a conexão real com o cliente/driver usado em produção, não apenas com o mysql CLI — como visto no passo 3, o cliente da aplicação pode ter uma limitação que o CLI não tem.
Nota para MySQL gerenciado (RDS/Aurora)
Em RDS/Aurora, o mesmo roteiro de mysql.user, host matching e plugin de autenticação se aplica normalmente — mas a recuperação de senha do usuário master não passa por --skip-grant-tables (o acesso ao host não existe em serviço gerenciado). O fluxo exato de reset do master user deve ser via console/CLI da AWS, pois pode variar entre engine e versão — confirme na documentação oficial antes de aplicar em produção.
Esse tipo de erro custa tempo de diagnóstico quando tratado como "só trocar a senha". Ter o roteiro (host, plugin, log, grants) reduz o vaivém entre tentativa e erro — e evita reabrir o mesmo chamado na semana seguinte.


Comentários