deplaneDocs Dashboard

MySQL

A managed MySQL 8.4 for your apps: one server, backed up every night, attached to your apps as MYSQL_URL.

What you get

Each MySQL is MySQL Community Server 8.4 LTS, from the unmodified upstream image. It is a single instance: one server, with no live copy on another server (see Availability). It has one database, app, and one user, app, with all rights on that database and nothing else. The server's character set is utf8mb4. It runs in its own microVM, reachable only by the apps you attach it to; it has no public address.

$ deplane mysql create shop
$ deplane mysql attach shop --app web

The first start takes about 30 seconds. An app has one MySQL, a MySQL may serve several of your apps (and their workers and cron jobs), and an app may also have a Postgres database and a Redis. Pull request previews do not get the MySQL.

In the dashboard, open Databases and find MySQL.

Sizes

SizeMemoryCPUBuffer poolConnectionsStorage
medium (default)1 GB1 vCPU384 MB10010 GB
large2 GB2 vCPU1 GB20010 GB

Pick the size when you create it: deplane mysql create shop --size large. A MySQL counts as one instance of its size against your plan, like an app instance. No small size: MySQL 8.4 and its microVM need more than 512 MB. In our tests a medium MySQL used 243 MB at rest and at most 682 MB with 16 busy clients on 920 MB of data.

Connect

Attaching sets MYSQL_URL on the app and rolls out a new release with it:

mysql://app:PASSWORD@my--NAME:3306/app

The parts:

PartValue
Hostmy--NAME, for example my--shop
Port3306
Userapp
Password32 random letters and digits, only inside MYSQL_URL
Databaseapp

Deplane shows the password nowhere else. Many libraries take the URL as it is, for example mysql.createConnection(process.env.MYSQL_URL) with Node's mysql2. If your app wants the parts as separate settings, read them from MYSQL_URL when it starts. A template can set them for you with ${mysql.url}, ${mysql.host}, ${mysql.port}, ${mysql.user}, ${mysql.password} and ${mysql.database}.

A template that needs a MySQL creates and attaches one for you, named after the app (APP-mysql), at the size the template asks for (medium unless it says large). Deleting the template deploy ("Delete all of it") destroys that MySQL with its data, unless another app uses it by then.

A client on your own computer (MySQL Workbench, TablePlus, the mysql command) cannot connect, because the MySQL has no public address. Run SQL through one of your apps with deplane run instead. Most app images have no MySQL client: add one to your Dockerfile (apk add mysql-client on Alpine, apt-get install -y default-mysql-client on Debian), or use your app's own language. With a client in the image:

$ deplane run --app web -- sh -c 'p=${MYSQL_URL#mysql://app:}; MYSQL_PWD="${p%%@*}" mysql -h my--shop -u app app -e "SHOW TABLES"'

deplane run shows only the first 10 MB of output, so use it for queries and small exports, not for copying a large database.

Client notes

MySQL 8.4 signs users in with caching_sha2_password. Current clients do this without TLS: in our tests PHP's mysqlnd (the WordPress image) and Node's mysql2 (the Ghost image) both connected over a plain connection, also right after a restart. So the older mysql_native_password is off. A client that knows only that older method cannot sign in; update the client.

A few clients need a setting to sign in without TLS:

Traffic to the MySQL never leaves Deplane's private network, so TLS is not needed. It is available: the server has its own self-signed certificate. Use TLS without verifying the certificate (for example ssl-mode=REQUIRED); a check of the certificate against a known authority fails. Deplane does not manage MySQL certificates.

The app password

Keep the app password as it is: MYSQL_URL depends on it. If you change it (with SET PASSWORD, or a plugin or tool that does), your apps cannot connect with MYSQL_URL until the MySQL restarts. If you change it, Deplane sets it back at the next restart; a restore restarts it too. Backups and health checks sign in with a separate account of Deplane's, which can read your data for dumps but cannot write rows, so they keep working.

Backups and restore

Every MySQL is backed up every night, at a time of its own between 01:00 and 05:00 UTC. A backup is a full copy of the app database (tables, views, routines, triggers and events), taken while the MySQL keeps running, compressed, encrypted, with an off-site copy kept 7 days. Use InnoDB tables (the default): other kinds of tables are copied without a consistent snapshot.

Back it up now with deplane mysql backup NAME (once an hour, or 5 minutes after a backup failed) and list backups with deplane mysql backups NAME. Backups are kept for the backup window: 3 days, or your plan's backup retention if that is shorter. The newest backup that worked is kept longer, until a newer one works.

deplane mysql restore NAME BACKUP-ID replaces all the data of the MySQL NAME with a backup. It asks for your passkey. The backup can be from any MySQL of your team: its own, another one, or one you destroyed (list those with deplane mysql backups --destroyed). The MySQL stops while the restore runs, so its apps cannot connect, and it starts again by itself; data written since the backup is lost. The app password stays the MySQL's own, so MYSQL_URL keeps working.

How long it takes: in our tests, 920 MB of data backed up in 17 seconds (244 MB compressed) and loaded back in under 2 minutes. A full 10 GB takes about 3 minutes to back up and about 20 minutes to restore.

If a restore fails after it started replacing the data, the MySQL may start empty: restore again or email support@deplane.cloud. A restore that fails before then (the backup could not be downloaded, for example) leaves the data unchanged, and its message says so.

How much you can lose

A MySQL is backed up once a night. If its data is lost, you can lose up to about a day of data: there is no point-in-time restore. Back it up now before a risky change, such as a migration or an import. If you need restore to any second, use a Postgres database.

Availability

A MySQL is a single instance. If the server holding its disk goes down, the MySQL is down until that server returns; its apps cannot reach it meanwhile. If that server is lost, restoring a backup is the way out: create a new MySQL, restore the old one's latest backup into it, and attach your apps. This is the same promise as Redis and app disks. It is below Postgres databases, which keep a live copy on another server.

When the disk fills

A MySQL has a 10 GB disk for its data, its indexes and its temporary files, and it does not grow. When it is full, writes fail or wait, and large queries that need temporary space fail; reads keep working. Delete data you no longer need, then run OPTIMIZE TABLE on the tables you emptied to give the space back. To see how much the data takes:

SELECT ROUND(SUM(data_length + index_length) / 1024 / 1024) AS mb
FROM information_schema.tables WHERE table_schema = 'app';

The nightly backup keeps working while the disk is full.

Limits

See also Limits.

Destroy

deplane mysql destroy NAME removes MYSQL_URL from its apps and deletes the MySQL and its data. It asks for your passkey. Its backups are kept for the backup window (3 days at most), then deleted. Until then you can restore them into another MySQL: deplane mysql backups --destroyed lists them.

MySQL is a trademark of Oracle and/or its affiliates. Deplane is not affiliated with Oracle.

This page is also available as Markdown. AI agents can start at /llms.txt.