Este guia cobre a instalação do MySQL 9.7.0 puro (sem MariaDB, sem pacotes de distro) usando o tarball genérico oficial da Oracle, válido para Debian, Arch Linux, Fedora e openSUSE. O procedimento de instalação e o arquivo de serviço systemd são idênticos nas quatro distribuições — apenas as dependências variam.
Por que tarball genérico? Os pacotes de repositório das distros frequentemente instalam o MariaDB ou uma versão desatualizada do MySQL. O binário genérico da Oracle garante a versão exata que você escolheu, sem conflitos com o gerenciador de pacotes.
1. Download do Tarball Genérico
O arquivo é único para todas as distros — é um binário compilado contra glibc, independente de distribuição. Só muda se sua arquitetura for ARM (aarch64) em vez de x86_64.
O site da Oracle usa JavaScript e redirecionamentos com token temporário, portanto não é possível usar uma URL fixa diretamente. Siga os passos abaixo para obter a URL real:
- Acesse https://dev.mysql.com/downloads/mysql/
- Selecione: Innovation → 9.7.0 → Linux – Generic → x86_64
- Clique em Download e depois em "No thanks, just start my download"
- Copie o link real — terá o formato:
https://cdn.mysql.com//Downloads/MySQL-9.7/mysql-9.7.0-linux-glibc2.28-x86_64.tar.xz
Com a URL em mãos, baixe com wget:
wget -c --show-progress \
"https://cdn.mysql.com//Downloads/MySQL-9.7/mysql-9.7.0-linux-glibc2.28-x86_64.tar.xz" \
-O /usr/local/src/mysql-9.7.0.tar.xz
Ou com curl:
curl -L --progress-bar \
"https://cdn.mysql.com//Downloads/MySQL-9.7/mysql-9.7.0-linux-glibc2.28-x86_64.tar.xz" \
-o /usr/local/src/mysql-9.7.0.tar.xz
Após o download, verifique a integridade (compare com o MD5/SHA256 exibido na página de download):
md5sum /usr/local/src/mysql-9.7.0.tar.xz
sha256sum /usr/local/src/mysql-9.7.0.tar.xz
2. Dependências por Distribuição
Execute os comandos abaixo como root na sua distro antes de prosseguir.
Debian / Ubuntu
apt update
apt install -y libaio1t64 libncurses5 libssl3 libnuma1 xz-utils
# Em Debian mais antigo ou Ubuntu LTS sem libaio1t64:
apt install -y libaio1 || apt install -y libaio1t64
Arch Linux
pacman -Sy --noconfirm libaio ncurses openssl numactl xz
Fedora / RHEL / Rocky / AlmaLinux
dnf install -y libaio ncurses-libs openssl-libs numactl-libs xz
# Necessário no EL8 e EL9 para o cliente mysql funcionar:
dnf install -y ncurses-compat-libs
openSUSE Leap / Tumbleweed
zypper install -y libaio1 libncurses6 libopenssl3 libnuma1 xz
Nota openSUSE Leap antigo: substitua
libncurses6porlibncurses5se sua versão for anterior ao Leap 15.4.
3. Criar Usuário e Grupo mysql
Idêntico em todas as distros:
groupadd mysql
useradd -r -g mysql -s /bin/false -d /usr/local/mysql mysql
O flag -r cria uma conta de sistema (sem login interativo), e -s /bin/false impede qualquer acesso via shell.
4. Extrair e Posicionar os Binários
cd /usr/local
tar xJf /usr/local/src/mysql-9.7.0.tar.xz
# Cria o symlink canônico — facilita upgrades futuros
ln -s mysql-9.7.0-linux-glibc2.28-x86_64 mysql
cd mysql
# Diretório para importação/exportação segura (secure_file_priv)
mkdir mysql-files
chown mysql:mysql mysql-files
chmod 750 mysql-files
# Binários pertencem ao root; apenas os dados pertencem ao mysql
chown -R root .
chown -R mysql data
5. Arquivo de Configuração
Crie (ou edite) o arquivo /etc/my.cnf:
[mysqld]
basedir = /usr/local/mysql
datadir = /usr/local/mysql/data
socket = /var/run/mysqld/mysqld.sock
pid-file = /var/run/mysqld/mysqld.pid
log-error = /var/log/mysql/error.log
secure-file-priv = /usr/local/mysql/mysql-files
# Ajuste conforme sua RAM (regra geral: 50–70% da RAM disponível)
innodb_buffer_pool_size = 512M
[client]
socket = /var/run/mysqld/mysqld.sock
Crie os diretórios de runtime e log:
mkdir -p /var/run/mysqld /var/log/mysql
chown mysql:mysql /var/run/mysqld /var/log/mysql
6. Inicializar o Data Directory
/usr/local/mysql/bin/mysqld \
--initialize \
--user=mysql \
--basedir=/usr/local/mysql \
--datadir=/usr/local/mysql/data
O MySQL gera uma senha temporária de root durante a inicialização. Anote-a:
grep 'temporary password' /var/log/mysql/error.log
Importante: se você perder essa senha, precisará reinicializar o data directory com
--initializenovamente, o que apaga todos os dados.
7. Criar o Serviço systemd
Crie o arquivo /etc/systemd/system/mysql.service com o conteúdo abaixo. Este unit é compatível com todas as quatro distribuições:
[Unit]
Description=MySQL 9.7.0 Database Server
Documentation=https://dev.mysql.com/doc/refman/9.7/en/
After=network.target
After=syslog.target
[Service]
Type=notify
# Usuário e grupo
User=mysql
Group=mysql
# Inicialização
ExecStart=/usr/local/mysql/bin/mysqld \
--basedir=/usr/local/mysql \
--datadir=/usr/local/mysql/data \
--socket=/var/run/mysqld/mysqld.sock \
--pid-file=/var/run/mysqld/mysqld.pid \
--log-error=/var/log/mysql/error.log
ExecReload=/bin/kill -HUP $MAINPID
# Garante criação automática do diretório /var/run/mysqld com permissão correta
RuntimeDirectory=mysqld
RuntimeDirectoryMode=0755
# Reinicia automaticamente em caso de falha inesperada
Restart=on-failure
RestartSec=5s
# Limites de recursos
LimitNOFILE=65535
LimitNPROC=65535
LimitCORE=0
# Timeout generoso para bancos grandes
TimeoutStartSec=900
[Install]
WantedBy=multi-user.target
8. Ativar e Iniciar o Serviço
# Recarrega o systemd para reconhecer o novo unit
systemctl daemon-reload
# Habilita o MySQL para iniciar junto com o sistema
systemctl enable mysql
# Inicia o serviço agora
systemctl start mysql
# Verifica o status
systemctl status mysql
Para acompanhar os logs em tempo real:
journalctl -u mysql -f
9. Adicionar os Binários ao PATH (Opcional)
Para usar comandos como mysql, mysqldump e mysqlcheck diretamente no terminal, sem informar o caminho completo:
echo 'export PATH=/usr/local/mysql/bin:$PATH' >> /etc/profile.d/mysql.sh
source /etc/profile.d/mysql.sh
10. Pós-instalação — Trocar a Senha e Proteger o Servidor
Conecte usando a senha temporária obtida no passo 6:
/usr/local/mysql/bin/mysql -u root -p
Dentro do prompt do MySQL, troque a senha imediatamente:
ALTER USER 'root'@'localhost' IDENTIFIED BY 'SuaSenhaForte!123';
FLUSH PRIVILEGES;
Alternativamente, use o assistente interativo que remove contas anônimas, desabilita acesso root remoto e remove o banco de teste:
/usr/local/mysql/bin/mysql_secure_installation
Resumo: Diferenças entre as Distribuições
| Distribuição | Detalhe específico |
|---|---|
| Debian 12+ / Ubuntu 24+ | libaio1 foi renomeado para libaio1t64; verifique com apt search libaio |
| Arch Linux | Pacotes com os nomes exatos: libaio, ncurses, numactl |
| Fedora / EL8 / EL9 | Necessário instalar ncurses-compat-libs para o cliente mysql funcionar |
| openSUSE | Tumbleweed usa libncurses6; Leap antigo usa libncurses5 |
O tarball, a estrutura de diretórios, o my.cnf e o unit systemd são idênticos nas quatro distribuições.
Referências
- MySQL 9.7 — Installing MySQL on Unix/Linux Using Generic Binaries
- MySQL 9.7 — Postinstallation Setup and Testing
- MySQL Community Downloads
Exercícios
Exercício 1
Execute mentalmente o passo 4 na ordem escrita. O tarball genérico traz bin/, lib/, share/, support-files/ — e não traz um diretório data. O que acontece nas duas últimas linhas?
Ver resposta
✓ Resposta: As duas falham no objetivo, cada uma de um jeito.
chown -R mysql data imprime cannot access 'data': No such file or directory e sai com erro. O data só nasce no passo 6, criado pelo --initialize — que, aliás, já o cria com o dono certo, então essa linha aqui é inútil de qualquer forma.
A que morde de verdade é a anterior. chown -R root . é recursivo a partir de /usr/local/mysql e passa por cima do mysql-files que acabou de ser ajustado três linhas acima. Como chown root sem grupo preserva o grupo, o diretório termina assim:
drwxr-x--- root mysql mysql-files/
Com 750, o grupo tem apenas r-x. O servidor roda como mysql, então ele lê desse diretório mas não escreve — e é justamente ele o secure-file-priv do my.cnf. O sintoma aparece muito depois da instalação, quando alguém tenta um SELECT ... INTO OUTFILE e recebe erro de permissão sem relação óbvia com a causa.
A ordem correta é a da documentação oficial: inicializar primeiro, ajustar donos depois, e incluir mysql-files junto com data:
bin/mysqld --initialize --user=mysql
chown -R root .
chown -R mysql data mysql-files
O padrão que isso ensina vale além do MySQL: chown -R desfaz, sem avisar, todo ajuste fino feito antes dele na mesma árvore. Permissão específica se aplica depois da recursiva, nunca antes.
Exercício 2
O passo 6 afirma: "se você perder essa senha, precisará reinicializar o data directory com --initialize novamente, o que apaga todos os dados". Avalie essa frase.
Ver resposta
✓ Resposta: É falsa, e perigosamente — alguém que acredite nela pode destruir um banco de produção para resolver um problema que se conserta em dois minutos.
A senha de root vive numa tabela do próprio banco (mysql.user). Perder a senha é perder o acesso, não os dados, e o MySQL tem um procedimento documentado para retomá-lo. O caminho recomendado é o --init-file, porque não abre o servidor sem autenticação em momento nenhum:
# 1. parar o serviço
systemctl stop mysql
# 2. arquivo com o comando de reset
printf "ALTER USER 'root'@'localhost' IDENTIFIED BY 'NovaSenhaForte!123';\n" \
> /var/lib/mysql-reset.sql
chown mysql:mysql /var/lib/mysql-reset.sql
# 3. subir uma vez executando esse arquivo no boot
/usr/local/mysql/bin/mysqld --user=mysql --init-file=/var/lib/mysql-reset.sql
# 4. encerrar, apagar o arquivo e voltar ao normal
rm /var/lib/mysql-reset.sql
systemctl start mysql
A alternativa mais conhecida é --skip-grant-tables, e ela pede cuidado: nesse modo o servidor aceita qualquer conexão sem senha. Se for usada, sempre com --skip-networking junto, para restringir ao socket local.
Um detalhe que também desmonta a premissa da frase: o --initialize se recusa a rodar sobre um datadir que não esteja vazio. Ele não apagaria os dados — ele abortaria. Para chegar ao desastre descrito seria preciso apagar o diretório manualmente antes.
Exercício 3
O passo 1 manda rodar md5sum e sha256sum e comparar com o valor exibido na página de download. Contra que ameaça isso protege — e contra qual não protege?
Ver resposta
✓ Resposta: Protege contra corrupção: download interrompido, erro de disco, proxy que estragou o arquivo. Nesses casos o hash diverge e você repete o download.
Não protege contra adulteração, porque o arquivo e o hash de referência vêm da mesma origem. Quem consegue trocar o tarball no CDN consegue trocar o número na página ao lado — e você compara a cópia falsa com o hash da cópia falsa, obtendo um ✅ perfeito. O hash publicado junto do arquivo verifica integridade, não autenticidade.
O que fecha essa lacuna é assinatura. A Oracle publica um .asc para cada release, assinado com a chave GPG do MySQL Release Engineering:
# chave pública da Oracle/MySQL, obtida uma vez e por canal confiável
gpg --import mysql_pubkey.asc
wget https://cdn.mysql.com//Downloads/MySQL-9.7/mysql-9.7.0-linux-glibc2.28-x86_64.tar.xz.asc
gpg --verify mysql-9.7.0-linux-glibc2.28-x86_64.tar.xz.asc \
/usr/local/src/mysql-9.7.0.tar.xz
A diferença é onde mora a confiança: no GPG ela está na chave que você já tem, não no servidor que serviu o arquivo agora. Falsificar a assinatura exige a chave privada da Oracle — comprometer o CDN não basta.
Vale ligar isso à premissa do artigo. A justificativa para o tarball genérico é fugir do que a distro empacota — mas é exatamente isso que o apt e o dnf fazem por você a cada instalação: verificam assinatura antes de instalar, com a chave do repositório já confiada. Ao sair do gerenciador de pacotes, essa verificação passa a ser sua. E o md5sum, ainda por cima, usa um algoritmo em que colisões são produzidas há anos.
Exercício 4
O passo 5 cria /var/run/mysqld com mkdir -p, e o unit do passo 7 declara RuntimeDirectory=mysqld. Parece redundante. Reinicie a máquina e diga o que sobrou de cada um.
Ver resposta
✓ Resposta: Do mkdir não sobra nada. Do RuntimeDirectory sobra o serviço funcionando — e é ele que faz o trabalho de verdade.
/var/run é um link para /run, que é tmpfs: existe só em memória e é recriado vazio a cada boot. O diretório criado à mão serve para a instalação de hoje e desaparece no próximo reinício. Sem o RuntimeDirectory, o MySQL falharia ao subir no boot seguinte por não conseguir criar o socket — uma falha que só aparece no primeiro reboot, tipicamente semanas depois, quando ninguém associa mais ao dia da instalação.
O que a diretiva do systemd faz, e o mkdir não faz:
- cria
/run/mysqlda cada start, antes doExecStart; - aplica dono e grupo do
User=/Group=automaticamente, e o modo doRuntimeDirectoryMode; - remove o diretório quando o serviço para, junto com socket e pid órfãos.
Esse último ponto merece atenção porque tem um efeito colateral: enquanto o serviço está parado, /run/mysqld não existe. Uma ferramenta que aponte para o socket via [client] socket = /var/run/mysqld/mysqld.sock reclama de caminho inexistente em vez de "conexão recusada" — mensagem diferente, mesma causa.
O mkdir manual não é totalmente inútil: ele permite rodar o --initialize do passo 6, que acontece antes de o serviço existir. O erro seria acreditar que ele basta. Já /var/log/mysql, criado na mesma linha, é persistente — esse sim precisa do mkdir.
Exercício 5
O unit usa Type=notify com TimeoutStartSec=900. Um serviço de aplicação declara After=mysql.service e Requires=mysql.service. O que muda para essa aplicação se o tipo fosse Type=simple?
Ver resposta
✓ Resposta: Com Type=simple, a aplicação sobe antes de o MySQL aceitar conexões e falha no boot com "connection refused".
A diferença está em quando o systemd considera o serviço iniciado:
Type=simple: no instante em que consegue executar o binário. O processo existe — mas o MySQL ainda vai abrir tablespaces, aplicar o redo log e recuperar transações pendentes. Em base grande isso leva minutos.Type=notify: quando o próprio mysqld avisa pelosd_notifyque terminou de inicializar e está pronto. OAfter=da aplicação passa a significar o que se espera dele.
É por isso que o TimeoutStartSec=900 só faz sentido acompanhado de Type=notify. Com simple ele não teria o que medir — não há evento de "pronto" a esperar. Com notify, ele é a folga que impede o systemd de declarar falha e matar um servidor que está legitimamente recuperando um banco grande. Reduzi-lo para o padrão de 90 segundos produz um modo de falha cruel: o systemd mata o mysqld no meio da recuperação, o Restart=on-failure o sobe de novo, a recuperação recomeça do zero, e o ciclo se repete.
Uma ressalva que evita a conclusão fácil: notify garante que o processo terminou de inicializar, não que o banco esteja em estado utilizável para a aplicação — migrações pendentes, réplica atrasada e permissões faltando continuam sendo problema dela. Ordenar no systemd elimina a corrida do boot; não substitui retry com espera na própria aplicação, que é o que a protege quando o banco cai depois, com tudo já em pé.