Como instalar MySQL no Ubuntu e criar banco de dados (passo a passo)

Aprenda a instalar MySQL Ubuntu e criar banco de dados do zero: configuração segura, usuário dedicado, permissões e teste de conexão remota.

MySQL ainda é o banco relacional mais usado em aplicações web — Laravel, Django, Rails, Node.js, todos têm suporte de primeira classe. Mas a instalação default em Ubuntu deixa pontas soltas: usuário root sem senha forte, ausência de banco da aplicação, e configuração de rede que ou bloqueia conexões legítimas ou expõe a porta 3306 pro mundo.

Este guia cobre o caminho completo numa VPS Ubuntu 24.04 LTS: instalação dos pacotes oficiais, hardening básico com mysql_secure_installation, criação de um banco dedicado pra sua aplicação, criação de usuário com permissões mínimas necessárias e validação da conexão. Persona alvo: developer que precisa de um MySQL local funcional pra rodar a aplicação em staging ou produção pequena.

Tempo estimado de execução: 15 a 20 minutos contando os reinícios de serviço e o teste de conexão pela aplicação.

Pré-requisitos

Antes de começar, confirme que sua VPS atende ao mínimo abaixo. Se você ainda não tem o servidor configurado, o tutorial assume acesso SSH funcional como usuário com sudo.

Pré-requisitos

Ubuntu 24.04 LTS (também funciona em 22.04), acesso SSH com usuário sudo, mínimo 1 GB de RAM (MySQL 8 consome ~400 MB ocioso), e ~500 MB livres em disco pros pacotes e o data directory inicial em /var/lib/mysql.

Versão alvo MySQL 8.0.x
Porta padrão 3306
Data dir /var/lib/mysql
Config principal /etc/mysql/mysql.conf.d/mysqld.cnf

Se você ainda precisa decidir entre rodar tudo numa VPS ou separar banco em servidor dedicado, a regra prática é: até ~5k usuários ativos/dia, MySQL e aplicação na mesma VPS economiza latência de rede e simplifica deploy. Acima disso, separe em instâncias dedicadas.

Instalação do MySQL Server

O Ubuntu 24.04 já inclui MySQL 8.0 nos repositórios oficiais — não precisa adicionar PPA externo. Esta seção cobre a instalação dos pacotes, primeiro start do serviço e verificação de que o daemon subiu corretamente.

01

Atualize o índice de pacotes do APT:

sudo apt update

Esse comando sincroniza a lista local com os repositórios configurados. Pular essa etapa pode resultar em instalação de versão antiga ou erro “package not found” mesmo o pacote estando disponível.

02

Instale o pacote mysql-server:

sudo apt install -y mysql-server

O instalador baixa o servidor, o cliente CLI (mysql) e dependências como libmysqlclient21. Em VPS com link de 100 Mbps a instalação completa leva ~30 segundos.

03

Verifique que o serviço está rodando:

sudo systemctl status mysql

A saída deve mostrar active (running) em verde. Se aparecer inactive ou failed, rode sudo journalctl -u mysql -n 50 pra ver o erro — em 90% dos casos é falta de memória (matar processos desnecessários ou aumentar swap resolve).

04

Habilite o start automático no boot:

sudo systemctl enable mysql

Sem isso, o MySQL não sobe após reinicialização da VPS — bug comum que só aparece no primeiro reboot de manutenção, geralmente meses depois.

Hardening inicial com mysql_secure_installation

O MySQL recém-instalado tem várias configurações inseguras pra facilitar o primeiro uso: banco de teste público, usuários anônimos, root acessível remotamente. O script mysql_secure_installation resolve tudo de uma vez.

05

Execute o script interativo:

sudo mysql_secure_installation

Ele vai te perguntar sequencialmente:

  • Validate password component: responda Y e escolha nível 2 (STRONG) — força senhas com 8+ caracteres, mistura de casos, números e símbolos.
  • Set root password: defina uma senha forte e guarde no seu gerenciador (1Password, Bitwarden, KeePassXC). Você vai precisar pras próximas etapas.
  • Remove anonymous users: Y.
  • Disallow root login remotely: Y — root só deve acessar via socket local.
  • Remove test database: Y.
  • Reload privilege tables: Y.
Sobre o auth_socket do root

No MySQL 8 do Ubuntu, mesmo após definir senha pro root, o login sudo mysql ainda funciona sem prompt — isso porque o root usa auth_socket por padrão, que confia no UID do sistema operacional. Comportamento esperado e seguro pra administração local.

Criando o banco de dados e o usuário da aplicação

Nunca use o usuário root pra conexões da sua aplicação. A boa prática é criar um banco dedicado e um usuário com permissões restritas só àquele banco — assim, comprometimento da aplicação não vira comprometimento do MySQL inteiro.

06

Conecte no MySQL como root:

sudo mysql

Você verá o prompt mysql>. Todos os comandos a seguir são SQL — terminam com ponto e vírgula.

07

Crie o banco de dados com encoding UTF-8 completo:

CREATE DATABASE meu_app
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_unicode_ci;

Use sempre utf8mb4 (não utf8 puro) — o utf8 do MySQL legado armazena apenas 3 bytes por caractere e quebra com emojis e caracteres CJK. O utf8mb4_unicode_ci faz ordenação case-insensitive correta pra português, espanhol e demais idiomas latinos.

08

Crie o usuário da aplicação com senha forte:

CREATE USER 'app_user'@'localhost'
  IDENTIFIED BY 'SenhaForteAqui123!@#';

Substitua SenhaForteAqui123!@# por uma senha gerada aleatoriamente — openssl rand -base64 24 no terminal gera uma string adequada. O @'localhost' restringe esse usuário a conexões locais (via socket Unix). Se sua aplicação roda em outro servidor, troque por @'10.0.0.5' (IP específico) ou em último caso @'%'.

09

Conceda permissões apenas no banco da aplicação:

GRANT ALL PRIVILEGES ON meu_app.*
  TO 'app_user'@'localhost';

FLUSH PRIVILEGES;

ALL PRIVILEGES ON meu_app.* dá controle total dentro daquele banco (CREATE, ALTER, INSERT, UPDATE, DELETE, SELECT, INDEX) mas zero acesso a outros bancos. Pra deploys onde a aplicação não cria tabelas em runtime (migrations rodam separadas), você pode restringir ainda mais: GRANT SELECT, INSERT, UPDATE, DELETE ON meu_app.* TO ....

10

Saia do prompt MySQL:

EXIT;
Princípio do menor privilégio

Em produção crítica, considere ter dois usuários: um pra migrations (com ALL PRIVILEGES, usado só no deploy) e outro pra runtime da aplicação (só SELECT/INSERT/UPDATE/DELETE). Limita o blast radius se um SQL injection passar.

Verificação da configuração

Antes de apontar a aplicação pro banco, valide tudo via CLI. Se falhar aqui, falha lá também — economiza tempo de debug.

11

Teste o login do usuário da aplicação:

mysql -u app_user -p meu_app

Digite a senha quando solicitada. Se entrar e mostrar mysql> sem erro, autenticação e permissão estão corretas.

12

Crie uma tabela de teste e insira um registro:

CREATE TABLE health_check (
  id INT AUTO_INCREMENT PRIMARY KEY,
  checked_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO health_check () VALUES ();
SELECT * FROM health_check;

A saída deve mostrar uma linha com id=1 e a data/hora atual. Se der erro de permissão, volte ao Step 09 e confirme o GRANT.

13

Limpe a tabela de teste:

DROP TABLE health_check;
EXIT;

Configurando acesso pela aplicação

Com o banco e o usuário criados, atualize o arquivo de configuração da aplicação. Os exemplos cobrem os formatos mais comuns.

Pra Laravel (.env):

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=meu_app
DB_USERNAME=app_user
DB_PASSWORD=SenhaForteAqui123!@#

Pra Node.js com mysql2:

DATABASE_URL=mysql://app_user:SenhaForteAqui123!%40%[email protected]:3306/meu_app

Note o URL-encoding na senha: ! vira %21, @ vira %40, # vira %23. Esquecer disso resulta em erro de autenticação confuso.

Nunca commite senhas

Adicione .env ao .gitignore antes do primeiro commit. Senha de banco vazada em repositório público é uma das causas mais comuns de invasão — bots varrem o GitHub Search constantemente atrás de strings tipo DB_PASSWORD=.

Resolução de problemas

Erro “Access denied for user ‘app_user’@‘localhost’”

A senha digitada não bate com o hash armazenado. Causas comuns:

  • Caractere especial não escapado no .env (use aspas duplas em volta da senha).
  • O usuário foi criado com @'127.0.0.1' mas a aplicação conecta como localhost (que vira socket) — ou vice-versa. Crie um usuário pra cada host que precisar.
  • Senha foi alterada via SET PASSWORD em vez de ALTER USER, que em algumas versões mantém hash antigo.

Resolução rápida:

ALTER USER 'app_user'@'localhost'
  IDENTIFIED BY 'NovaSenha';
FLUSH PRIVILEGES;

MySQL não aceita conexão remota

Por padrão o MySQL 8 escuta apenas em 127.0.0.1. Pra aceitar conexões de outras VMs na mesma rede privada, edite /etc/mysql/mysql.conf.d/mysqld.cnf:

bind-address = 0.0.0.0

Reinicie o serviço e libere a porta no firewall só pros IPs autorizados:

sudo systemctl restart mysql
sudo ufw allow from 10.0.0.0/24 to any port 3306

Nunca libere 3306 pra 0.0.0.0/0 sem TLS configurado.

”Too many connections”

O default de max_connections é 151. Pra aplicações com pool grande, aumente em mysqld.cnf:

max_connections = 500

Cada conexão consome ~12 MB de RAM — calcule conforme o tamanho da VPS antes de subir esse número.

Próximos passos

Com o MySQL funcional, vale considerar:

  • Backup automático: configure mysqldump em cron diário e replique o .sql pra storage externo (S3, Backblaze B2). Sem backup off-site, um disco corrompido apaga tudo.
  • Monitoramento: instale mysqltuner (sudo apt install mysqltuner) e rode após 24h de uso pra recomendações de tuning baseadas no workload real.
  • TLS pra conexões remotas: se vai expor 3306 pra outra VPS, configure certificados — o MySQL 8 suporta TLS nativamente.
  • Replicação read-only: pra aplicações com leitura intensa, configure uma réplica secundária e direcione SELECTs pra ela.
  • VPS dedicada pro banco: se sua aplicação cresceu, separar o MySQL numa VPS Hostini dedicada com SSD NVMe e backup snapshot reduz contenção de I/O entre app e banco.

Perguntas frequentes

MySQL ou MariaDB no Ubuntu 24.04?

Pra novos projetos, MySQL 8.0 entrega features mais recentes (CTEs, window functions, JSON nativo otimizado) e é o que a maioria dos ORMs documenta primeiro. MariaDB é fork compatível e tem performance ligeiramente melhor em alguns workloads de leitura, mas se sua aplicação fala MySQL, fique no MySQL pra evitar incompatibilidades sutis em features novas.

Posso conectar no MySQL de outro servidor sem expor a porta 3306?

Sim, e essa é a abordagem recomendada. Use um túnel SSH (ssh -L 3306:localhost:3306 user@servidor) ou deixe o MySQL escutando em 127.0.0.1 e coloque a aplicação na mesma VPS. Expor 3306 publicamente só faz sentido com firewall restritivo por IP e TLS obrigatório.

Qual a diferença entre usuário 'root'@'localhost' e 'root'@'%'?

O sufixo após @ define de onde aquele usuário pode conectar. 'root'@'localhost' só aceita conexão via socket local; 'root'@'%' aceita de qualquer IP. Pra root sempre use localhost. Pra app, crie usuário com host específico ('app'@'10.0.0.5') ou '%' apenas quando o firewall já restringe IPs.

O mysql_secure_installation removeu o usuário anônimo, mas ainda consigo logar sem senha. Por quê?

Você provavelmente está logado como root no sistema operacional, e o MySQL 8 usa auth_socket por padrão pro root local — não pede senha porque confia no usuário do SO. Pra forçar senha, altere com ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'senha'.

Como faço backup do banco depois de criá-lo?

Use mysqldump -u root -p nome_do_banco > backup.sql pra dump SQL completo, ou mysqldump --single-transaction pra bancos InnoDB sem travar tabelas. Pra restore: mysql -u root -p nome_do_banco < backup.sql. Em produção, automatize com cron diário e mantenha pelo menos 7 dias de retenção em storage separado.

Preciso reiniciar o MySQL toda vez que mudo my.cnf?

Sim, mudanças em /etc/mysql/mysql.conf.d/mysqld.cnf exigem sudo systemctl restart mysql pra ter efeito. Algumas variáveis são dinâmicas e podem ser ajustadas em tempo de execução com SET GLOBAL nome = valor, mas elas voltam ao padrão no próximo restart se não estiverem no arquivo.

Tópicos:
Próximos passos Cloud Ryzen com NVMe e proteção DDoS sempre ativa.Coloque em produção numa VPS Hostini →
Esse tutorial foi útil?
Falar no WhatsApp