Acentuação quebrada no MySQL: como corrigir o UTF-8

Se os acentos do seu site viraram símbolos estranhos — João em vez de João, informação em vez de informação —, o problema é de codificação de caracteres, e quase sempre aparece depois de exportar e importar um banco de dados. A causa mais comum é o mysqldump ou o phpMyAdmin gravando o arquivo num charset diferente do que o banco de destino espera.

A boa notícia: os dados não foram perdidos. Os bytes originais continuam lá — o que se perdeu foi a instrução de como interpretá-los. E na maioria dos casos dá para recuperar.

Resposta rápida

O que você vê diz onde está o problema:

João, informaçãoTexto UTF-8 sendo lido como latin1 — o caso mais comum
Jo?o, informa??oDados já convertidos com perda. Precisa restaurar backup
Jo�oByte inválido para o charset atual
Emojis somem ou viram ???O banco está em utf8 e não em utf8mb4

O que realmente está acontecendo

Um banco de dados não guarda letras — guarda números. Cada caractere é convertido em um ou mais bytes, e a tabela que define essa conversão é o charset (conjunto de caracteres).

O ã em UTF-8, por exemplo, ocupa dois bytes: C3 A3. Se um programa lê esses dois bytes achando que são latin1 — onde cada byte é um caractere —, ele exibe à e £. Daí o João.

Nada foi corrompido. Os bytes C3 A3 continuam exatamente onde estavam. O que falhou foi a instrução de como interpretá-los.

E é por isso que o problema costuma aparecer numa migração: o banco de origem falava um charset, o arquivo foi exportado noutro, e o banco de destino leu num terceiro. Basta um elo discordar para os acentos quebrarem.

Registros no phpMyAdmin com acentuação quebrada, exibindo ã em vez de ã

Os quatro pontos onde o charset é definido

Esta é a parte que a maioria dos tutoriais não explica, e é por ela que o problema volta mesmo depois de “corrigido”: o charset é declarado em quatro lugares diferentes, e todos precisam concordar.

Onde O que define
Banco e tabelas Como os dados são gravados em disco
Conexão Como a aplicação e o banco conversam
Aplicação (PHP, WordPress) Como o código trata o texto que recebe
Página HTML Como o navegador exibe o resultado

Um site pode ter o banco em UTF-8 e ainda assim mostrar acentos quebrados, se a conexão estiver em latin1. E o contrário também: banco em latin1 exibindo tudo certo, porque a conexão também está em latin1 — até o dia em que alguém exporta.

A regra é simples: use utf8mb4 nos quatro.

Atenção: utf8 no MySQL não é UTF-8

Um detalhe que resolve metade dos casos difíceis, e quase ninguém sabe.

Por razões históricas, o charset chamado utf8 no MySQL nunca foi o UTF-8 completo. Ele armazena no máximo 3 bytes por caractere, o que cobre acentos e a maioria dos idiomas, mas não cobre emojis nem alguns caracteres de línguas asiáticas.

O UTF-8 de verdade, com até 4 bytes, chama-se utf8mb4. Ele é o padrão desde o MySQL 8, mas bancos criados em versões anteriores costumam ter ficado no utf8 antigo.

Como isso aparece: os acentos funcionam normalmente, mas um emoji digitado num post ou num comentário some, vira ???, ou trunca o texto a partir dali.

⚠️ Sempre use utf8mb4, nunca utf8

Ao criar um banco novo, escolher tabelas ou definir a conexão, prefira sempre utf8mb4 com collation utf8mb4_unicode_ci. O utf8 antigo funciona para acentos, mas cria um problema latente que só aparece quando alguém usa um emoji — e aí a correção exige converter tudo de novo.

Como exportar sem quebrar os acentos

A causa mais frequente do problema. Duas formas de exportar, e o cuidado em cada uma:

Pelo phpMyAdmin: ao exportar, escolha o método Personalizado e confira o campo de conjunto de caracteres do arquivo. Ele deve estar em utf-8. No método Rápido, o phpMyAdmin usa o padrão do servidor — que nem sempre é o certo.

Exportação personalizada no phpMyAdmin com o conjunto de caracteres definido como utf-8

Pela linha de comando, o parâmetro é explícito:

mysqldump --default-character-set=utf8mb4 -u usuario -p nome_do_banco > backup.sql

E na importação, o mesmo cuidado:

mysql --default-character-set=utf8mb4 -u usuario -p nome_do_banco < backup.sql

Um detalhe que engana: abrir o arquivo .sql no Bloco de Notas e ver os acentos corretos não garante nada — o editor pode estar interpretando bem um arquivo que o MySQL vai interpretar mal. O que vale é o charset declarado na exportação.

Nosso guia sobre backup do banco pelo phpMyAdmin cobre o processo completo.

Como descobrir o charset atual do seu banco

Antes de corrigir, vale saber o que está configurado. No phpMyAdmin, abra a aba SQL e rode:

SELECT default_character_set_name, default_collation_name
FROM information_schema.SCHEMATA
WHERE schema_name = 'nome_do_banco';

E para ver tabela por tabela, que é onde as inconsistências aparecem:

SELECT table_name, table_collation
FROM information_schema.TABLES
WHERE table_schema = 'nome_do_banco';
Estrutura do banco no phpMyAdmin mostrando tabelas com agrupamentos diferentes

É comum encontrar um banco declarado em utf8mb4 com tabelas antigas ainda em latin1 — resquício de migrações passadas.

Aba Operações do phpMyAdmin mostrando o agrupamento atual do banco de dados

Corrigindo um banco que já está com acentos quebrados

Aqui a ordem importa, e o primeiro passo não é negociável.

1. Faça backup antes de qualquer coisa. Conversão de charset é irreversível, e uma conversão feita na direção errada destrói os dados de vez — transformando um problema de exibição num problema real de perda. O mesmo vale para o erro de inicialização do MySQL no XAMPP, em que a pressa de “resolver” apagando arquivos é o que costuma destruir os bancos.

2. Identifique o cenário. Há dois, e a solução é diferente:

Cenário Como identificar Solução
Só a leitura está errada Você vê João. Os bytes estão corretos, a interpretação não Ajustar o charset da conexão e das tabelas
Os dados já foram convertidos Você vê Jo?o. Os bytes originais foram substituídos Não há conversão que resolva — restaure um backup anterior

Aquele segundo caso é importante e pouco dito: quando os acentos viram ?, a informação se perdeu de fato. O ponto de interrogação é o que o MySQL grava quando não consegue representar um caractere no charset de destino, e não há como saber qual letra estava ali.

3. Converta as tabelas, se for o primeiro cenário:

ALTER TABLE nome_da_tabela
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Repita para cada tabela. Um banco WordPress tem cerca de doze tabelas — o phpMyAdmin permite selecionar todas de uma vez e aplicar a operação em lote.

4. Ajuste a aplicação. No WordPress, o charset fica no wp-config.php:

define( 'DB_CHARSET', 'utf8mb4' );
define( 'DB_COLLATE', '' );

Em PHP puro com PDO, o charset vai na string de conexão: mysql:host=localhost;dbname=banco;charset=utf8mb4.

5. Confira o HTML. Mesmo com tudo certo no banco, uma página sem <meta charset="utf-8"> exibe acentos quebrados. Nosso guia sobre caracteres especiais e acentos no HTML cobre esse lado.

O caso específico do WordPress

Alguns pontos que só aparecem no WordPress:

A migração é o momento de risco. Ao mover o site, o banco de origem pode estar em latin1 e o de destino em utf8mb4. A exportação sem charset explícito é o que quebra tudo.

O wp-config.php manda no comportamento. Se o DB_CHARSET não bater com o charset real das tabelas, o WordPress grava certo e lê errado — ou o contrário.

Sites antigos costumam estar em latin1. Instalações de antes de 2015 foram criadas assim, e continuam funcionando até o dia da migração.

Plugins de migração ajudam. Ferramentas como Duplicator e All-in-One WP Migration cuidam do charset automaticamente — é um argumento a favor de usá-las em vez do processo manual, sobretudo para quem não domina o assunto.

Migração feita por quem já viu esse problema

Acentuação quebrada é o erro mais comum de migração feita às pressas. Na Homehost, a migração é gratuita e conduzida pela nossa equipe — arquivos, banco e e-mails, com o charset conferido antes de entregar. Servidor no Brasil, NVMe e suporte em português, a partir de R$ 7,90/mês.

Ver planos de hospedagem

Perguntas frequentes

Por que os acentos do meu site viraram símbolos estranhos?

Porque o texto foi gravado num charset e está sendo lido em outro. O caso mais comum é conteúdo em UTF-8 sendo interpretado como latin1, o que transforma ção em ção. Os dados não foram perdidos: os bytes originais continuam no banco, e o que falhou foi a instrução de como interpretá-los.

Qual a diferença entre utf8 e utf8mb4 no MySQL?

O charset chamado utf8 no MySQL não é o UTF-8 completo — ele usa no máximo 3 bytes por caractere, o que cobre acentos mas não emojis nem alguns caracteres asiáticos. O utf8mb4 é o UTF-8 de verdade, com até 4 bytes. Use sempre utf8mb4.

Como exportar um banco MySQL sem quebrar a acentuação?

Pela linha de comando, use mysqldump --default-character-set=utf8mb4. No phpMyAdmin, escolha o método Personalizado e confirme que o conjunto de caracteres do arquivo está como utf-8 — o método Rápido usa o padrão do servidor, que nem sempre é o correto.

Meus acentos viraram pontos de interrogação. Dá para recuperar?

Não. O ponto de interrogação é o que o MySQL grava quando não consegue representar um caractere no charset de destino — a informação original foi substituída e não há como saber qual letra estava ali. A única saída é restaurar um backup anterior à conversão.

Como sei qual charset meu banco está usando?

No phpMyAdmin, a aba Operações do banco mostra o agrupamento (collation) atual. Para ver tabela por tabela, rode uma consulta em information_schema.TABLES filtrando pelo nome do seu banco — é comum encontrar bancos em utf8mb4 com tabelas antigas ainda em latin1.

Corrigi o banco mas os acentos continuam errados. Por quê?

O charset é definido em quatro lugares: banco e tabelas, conexão, aplicação e página HTML. Corrigir só um não basta — se a conexão continua em latin1, o problema persiste mesmo com as tabelas em utf8mb4. No WordPress, confira também o DB_CHARSET no wp-config.php.

Converter as tabelas para utf8mb4 é seguro?

A operação em si é padrão, mas é irreversível — e se os dados já estiverem em estado inconsistente, a conversão pode piorar. Faça backup do banco antes, sempre. Se a conversão der errado, o backup é a única forma de voltar atrás.

Por que isso acontece principalmente em migrações?

Porque a migração envolve três pontos onde o charset pode divergir: o banco de origem, o arquivo exportado e o banco de destino. Basta um deles discordar para os acentos quebrarem. Exportar e importar declarando utf8mb4 explicitamente evita o problema.

Veja também

Para entender o funcionamento do banco, veja o que é MySQL e os tipos de dados do MySQL. Sobre acentuação no lado do HTML, veja caracteres especiais e acentos. E se o site parou de conectar ao banco, veja erro ao estabelecer uma conexão com o banco de dados.

Conclusão

Acentuação quebrada assusta mais do que deveria: na maioria das vezes os dados estão intactos, e o que se perdeu foi só a instrução de como lê-los. O caminho é sempre o mesmo — descobrir em qual dos quatro pontos o charset diverge, alinhar todos em utf8mb4, e conferir se a aplicação e o HTML concordam. Duas coisas valem gravar: faça backup antes de qualquer conversão, porque ela é irreversível; e se os acentos viraram pontos de interrogação, não há conversão que resolva — ali a informação se foi, e só o backup traz de volta.

Este artigo foi útil?

Obrigado pela resposta!
Picture of Gustavo Gallas

Gustavo Gallas

Analista de sistemas, formado pela PUC-Rio. Programador, gestor de redes e diretor da empresa Homehost. Pai do Bóris, seu pet de estimação. Gosta de rock'n'roll, cerveja artesanal e de escrever sobre assuntos técnicos.

Contato: gustavo.blog@homehost.com.br

Ganhe 30% OFF

Indique seu nome e e-mail,e ganhe um cupom de desconto de 30% para sempre na Homehost!