UpuaiUpuai
MySQL gerenciado

MySQL gerenciado

Um MySQL por serviço, com a conta de aplicação criada e mantida pela plataforma. Conecte por referência, crie os bancos que precisar e troque a senha sem editar variável nenhuma.

Visão geral

Cada MySQL gerenciado roda numa instância própria dentro do seu ambiente, com disco persistente e backup lógico diário conforme o plano. A plataforma cria a conta que os seus serviços usam, guarda a credencial e a entrega nas variáveis do serviço do banco.

O banco é acessível pelos serviços do mesmo ambiente, pelo nome do serviço (por exemplo mysql:3306). Para conectar do seu computador (DBeaver, MySQL Workbench, TablePlus, mysqldump), ligue o acesso público na aba Conectar.

Criar um banco

Pelo canvas do projeto ou pela CLI. O banco fica pronto em cerca de três minutos; quando aparece como running, a conta já existe e o login já funciona.

Painel

Canvas do projeto → Add Service → Database → MySQL.

CLI

upuai add --type database --engine mysql --name mysql

Versões

MySQL 8.4 (padrão) ou 8.0, escolhida na criação.

Nome

O nome do serviço é o hostname do banco e a chave das referências. Ele não pode ser alterado depois: escolha o nome definitivo na criação.

Conectar um serviço

O serviço do banco expõe as variáveis abaixo. Use-as por referência no serviço que consome o banco: a referência é resolvida a cada deploy, então uma troca de senha chega ao serviço no deploy seguinte.

VariávelConteúdo
DATABASE_URLURL completa: mysql://usuário:senha@host:3306/banco.
HOSTHostname interno do banco (o nome do serviço).
PORT / MYSQL_PORT3306.
MYSQL_USERConta de aplicação (app).
MYSQL_PASSWORDSenha da conta. Gerada pela plataforma; troque pela rotação.
MYSQL_DATABASEBanco inicial (app).
terminal
# No serviço que consome o banco (o banco aqui se chama "mysql")
$ upuai variables set 'DATABASE_URL=${{mysql.DATABASE_URL}}' -s api
✓ Set DATABASE_URL [service]
ℹ Takes effect on the service's next deploy — run `upuai redeploy -s api` to apply it now.

$ upuai deploy -s api --wait --yes
✓ Deployment success

Para apontar um serviço para outro banco criado por você na mesma instância, monte a URL com as referências:

.env
# Outro banco criado por você dentro do mesmo MySQL
DATABASE_URL=mysql://${{mysql.MYSQL_USER}}:${{mysql.MYSQL_PASSWORD}}@${{mysql.HOST}}:3306/inkprint_master
No painel, o botão Connect database do serviço consumidor grava a referência para você. Depois de salvar uma variável, faça o deploy do serviço: variáveis só entram no container no deploy.

Conectar do seu computador

O acesso público abre o banco num endereço próprio, <slug>.db.upuai.cloud, numa porta exclusiva dele, com certificado TLS válido (Let's Encrypt). Fica desligado por padrão.

  • Ligue em: serviço do banco → aba Conectar → Acesso público (dono ou admin do workspace), ou pela CLI com upuai db public enable.
  • Cada banco tem a sua porta. Ela não muda se você desligar e religar o acesso; só some quando o banco é apagado.
  • Use verificação completa de identidade: --ssl-mode=VERIFY_IDENTITY no cliente mysql; no DBeaver, aba SSL → Use SSL + Verify server certificate; no MySQL Workbench, SSL → Require and Verify Identity; em JDBC, sslMode=VERIFY_IDENTITY.
  • O usuário é a conta de aplicação (MYSQL_USER) e a senha é a mesma das variáveis. A aba Conectar mostra host, porta, usuário, senha e banco em campos separados para clientes gráficos.
  • Restrinja quem pode conectar com a lista de IPs permitidos da mesma aba; fora dela a conexão é recusada antes de chegar ao banco.
terminal
# Host e porta: painel → serviço do banco → aba Conectar (ou `upuai db public status`)
# macOS: --ssl-ca=/etc/ssl/cert.pem · Debian/Ubuntu: /etc/ssl/certs/ca-certificates.crt
$ mysql --host=xq7zk3pm.db.upuai.cloud --port=23310 --user=app --password \
    --ssl-mode=VERIFY_IDENTITY --ssl-ca=/etc/ssl/cert.pem app

# Backup completo (rotinas, eventos, triggers e views)
$ mysqldump --host=xq7zk3pm.db.upuai.cloud --port=23310 --user=app --password \
    --ssl-mode=VERIFY_IDENTITY --ssl-ca=/etc/ssl/cert.pem \
    --single-transaction --routines --events --triggers --set-gtid-purged=OFF --no-tablespaces \
    app > backup.sql

# Restaurar
$ mysql --host=xq7zk3pm.db.upuai.cloud --port=23310 --user=app --password \
    --ssl-mode=VERIFY_IDENTITY --ssl-ca=/etc/ssl/cert.pem app < backup.sql
Bancos criados antes do acesso público reiniciam uma vez (cerca de 1 minuto) na primeira ativação, para carregar o certificado TLS — o painel pede confirmação antes. Depois disso, ligar e desligar não reinicia mais nada.

A conta de aplicação

A conta entregue em MYSQL_USER é a administradora dos seus dados naquela instância. Um app com um banco por cliente, por exemplo, cria os bancos com ela mesma.

O que a conta pode fazer

  • Criar, alterar e remover bancos, tabelas, índices e views.
  • Criar triggers, funções, procedures e eventos.
  • Criar outras contas e conceder a elas os privilégios que ela mesma tem — por exemplo uma conta só de leitura para BI.
  • Ler o estado do servidor (processos, status de replicação).
mysql
-- Conectado com a DATABASE_URL do serviço
SELECT CURRENT_USER(), VERSION();
-- app@%   8.4.6

CREATE DATABASE tenant_000001;
CREATE TABLE tenant_000001.orders (id INT PRIMARY KEY AUTO_INCREMENT, note VARCHAR(40));
CREATE TRIGGER tenant_000001.orders_bi BEFORE INSERT ON tenant_000001.orders
  FOR EACH ROW SET NEW.note = UPPER(NEW.note);
CREATE FUNCTION tenant_000001.one() RETURNS INT DETERMINISTIC RETURN 1;

-- Uma conta só de leitura para uma ferramenta de BI
CREATE USER 'bi_ro'@'%' IDENTIFIED BY '<senha>';
GRANT SELECT ON tenant_000001.* TO 'bi_ro'@'%';

O que fica com a plataforma

  • Não existe conta root. Privilégios de administração do servidor (variáveis globais, desligar, arquivos) não são entregues.
  • O schema de sistema mysql é somente leitura para a conta.
  • As contas com prefixo moco- são da plataforma (replicação, backup, monitoração). Não as altere nem remova: isso para o backup e a operação do seu banco.
  • A autenticação é caching_sha2_password, o padrão do MySQL 8. Use um driver atual (mysql2 no Node, mysqlclient/PyMySQL recentes, Connector/J 8+).

Senha: reparo e rotação

A credencial em uso fica guardada na plataforma, e as variáveis do serviço do banco são um espelho dela. Por isso elas são somente leitura: editar o texto de MYSQL_PASSWORD não mudaria a senha no banco.

  • Reparar: confere se a conta consegue logar e a reaplica se o banco a recusar (conta alterada por fora, por exemplo). Não troca a senha.
  • Rotacionar: gera uma senha nova. A senha atual deixa de abrir conexões na hora; conexões já abertas continuam até fecharem.
  • Depois de uma rotação, faça o deploy dos serviços listados no resultado: eles seguem com a senha antiga até lá.
  • No painel: serviço do banco → aba Database → Credenciais. Rotacionar exige dono ou admin do workspace.
  • Marcar uma variável do banco como segredo continua possível (ícone de cadeado na aba Variables), mas pense antes: o valor deixa de ser exibido no painel e na CLI, e para desmarcar é preciso informar o valor atual. Os serviços continuam recebendo a credencial por referência.
terminal
# Confere o login; reaplica a conta se o banco a recusar. Não troca a senha.
$ upuai db credentials repair -s mysql
✓ credentials are working — nothing to change

# Senha nova. A atual deixa de abrir conexões na hora.
$ upuai db credentials rotate -s mysql --yes
✓ password rotated — the previous one no longer opens connections
ℹ redeploy to pick up the current credential: api
ℹ read the new value with 'upuai variables list -s <database>'

$ upuai deploy -s api --wait --yes
✓ Deployment success

Tentar editar ou apagar uma variável de conexão do banco é recusado, com a indicação do caminho certo:

terminal
$ upuai variables set 'MYSQL_PASSWORD=outra-senha' -s mysql
✗ failed to set variables: API error 409: Connection variables of a managed database are set by
  the platform and cannot be edited or deleted. To change the password, rotate the database
  credentials. To use another database name or user, create it inside the database and reference
  it from the consuming service. (keys: MYSQL_PASSWORD; reason: databaseCredentialsReadOnly)
Um erro Access denied num MySQL gerenciado não se resolve apagando e recriando o banco, nem trocando por uma imagem Docker do MySQL — essa troca tira o backup gerenciado. Rode o reparo e, se a senha mudou, faça o deploy dos serviços listados.

Para agentes de IA

Receita determinística para Claude Code, Cursor e outros agentes que operam a CLI.

terminal
# 1. Ligar um serviço ao banco: sempre por referência, nunca colando a URL
upuai variables set 'DATABASE_URL=${{<db>.DATABASE_URL}}' -s <service>
upuai deploy -s <service> --wait --yes

# 2. "Access denied" num MySQL gerenciado
upuai db credentials repair -s <db>      # reaplica a conta se o banco a recusar
upuai deploy -s <service> --wait --yes   # só se o comando listar o serviço

# 3. Trocar a senha (dono ou admin)
upuai db credentials rotate -s <db> --yes
upuai deploy -s <service> --wait --yes   # cada serviço listado

# Nunca: apagar e recriar o banco, editar as variáveis dele,
# ou trocar por uma imagem Docker do MySQL para "resolver" um erro de acesso.
Os comandos upuai db credentials existem a partir da CLI v0.27.0. upuai ssh num MySQL gerenciado é recusado de propósito; para SQL, ligue o acesso público e conecte com um cliente MySQL, ou rode a partir de um dos seus serviços com a DATABASE_URL.

Erros e o que fazer

Códigos estáveis devolvidos pela API e pela CLI.

CódigoSignificado
ER_ACCESS_DENIED_ERROR (1045)O MySQL recusou usuário ou senha. Confira se o serviço usa a referência ${{banco.DATABASE_URL}} e se houve deploy depois da última troca de senha; então rode upuai db credentials repair.
ER_PLUGIN_IS_NOT_LOADED (1524)"Plugin 'mysql_native_password' is not loaded" no MySQL 8.4 quase sempre significa que o usuário da URL não existe no servidor (nome digitado errado ou URL de outro banco), não um problema de plugin. Confira a referência e rode upuai db credentials repair.
databaseCredentialsReadOnlyTentativa de editar ou apagar uma variável de conexão do banco. Para trocar a senha, use a rotação.
databaseRenameNotSupportedO nome de um banco gerenciado é o hostname dele e não pode ser alterado. Crie outro banco com o nome desejado.
mysqlOnlyReparo e rotação de credenciais existem para MySQL gerenciado.
DB_NOT_READYO banco ainda não está no ar (provisionando ou reiniciando). Espere ficar running e repita.
DB_OPERATION_IN_PROGRESSOutra operação está em andamento neste banco. Espere terminar e repita.

Perguntas frequentes

Posso usar outro nome de banco em vez de app?

Sim. Crie o banco com a conta de aplicação (CREATE DATABASE meu_banco) e monte a URL do serviço com as referências de usuário, senha e host, terminando em /meu_banco. O banco inicial app pode ficar vazio.

Preciso de root?

Não. A conta de aplicação cria bancos, tabelas, rotinas, triggers e outras contas. O que ela não tem é administração do servidor, que fica com a plataforma.

Rotacionei a senha e o meu app parou de conectar.

O container do app ainda tem a senha antiga. Faça o deploy do serviço: a referência ${{banco.DATABASE_URL}} é resolvida no deploy e passa a carregar a senha nova.

Colei a URL em vez de usar a referência. E agora?

Funciona, e a plataforma reescreve a senha dentro de URLs literais que apontam para o banco quando ela muda. Ainda assim prefira a referência: ela deixa explícito de onde o valor vem.

Como rodo SQL manualmente?

Ligue o acesso público e conecte do seu computador com o cliente mysql, DBeaver ou outro gerenciador (seção Conectar do seu computador). De dentro de um serviço seu, use a DATABASE_URL injetada. O acesso por shell ao serviço do banco não é oferecido.

Posso importar um dump?

Sim: com o acesso público ligado, restaure com mysql … < backup.sql do seu computador. Dumps com DEFINER de outro usuário ou com SET de variáveis globais precisam ser ajustados, porque a conta não tem privilégios de administração do servidor; dumps gerados da própria conta (mysqldump com as opções da seção acima) restauram direto.

Recursos