Overview
MySQL is the most widely used open-source relational database. This template deploys a single MySQL instance on a persistent volume, with an optional phpMyAdmin web console and an optional scheduledmysqldump to an S3 or GCS bucket.
Database credentials are not template values. MySQL reads the application credentials and the root password from two secrets you create before installing, so no password passes through Helm or lands in the release.
What Gets Created
Prerequisites
Two secrets must exist before you install. They are deliberately separate: an application or teammate givenreveal on the database credentials must not also receive root. Secrets are org-level, so no --gvc flag is involved.
Create the application credentials secret
username, password and database. MySQL creates this user and this database on first boot, and this is the credential your applications put in their connection strings.credentialsSecretName to this name.Create the root password secret
plain holding the MySQL root password.rootPasswordSecretName to this name.Installation
Install from the marketplace registry, passing the two secret names you created:UI
CLI
Terraform
Pulumi
Configuration
Image
Credentials
cpln://secret/... references, so the values appear in neither the Helm release nor the stored workload spec.
ALTER USER, then update the secret to match (see Troubleshooting).Resources
Internal Access
cpln port-forward, or from outside through your own proxy.
Storage
phpMyAdmin
reveal grant, and no password in its environment. It presents a login form, you supply either the application credentials or root plus the root password, and it connects to the database as whoever logged in. phpMyAdmin.internalAccess governs the console only — the database has its own internalAccess knob.
Backup
backup.provider to aws or gcp and fill in the matching section. The bucket, Cloud Account and permissions setup is under Backing Up.
Connecting
mysql client using the application credentials:
MYSQL_ROOT_PASSWORD:
Operations
Backing Up
Withbackup.enabled: true, the RELEASE_NAME-mysql-backup cron workload connects as root and runs mysqldump --databases DATABASE --single-transaction --set-gtid-purged=OFF against the database named in your credentials secret, gzips the result and uploads it as mysql-<UTC timestamp>.sql.gz under prefix in your bucket. Nothing is kept locally and nothing is ever deleted from the bucket — retention is whatever your bucket’s lifecycle rules say.
The bucket and the Cloud Account must exist before you enable it.
AWS S3
- Create an S3 bucket. Set
backup.aws.bucketto its name andbackup.aws.regionto its region. - Create a Control Plane Cloud Account for the AWS account holding the bucket. Set
backup.aws.cloudAccountNameto its name. - Create an IAM policy with the JSON below, replacing
YOUR_BUCKET_NAME, and setbackup.aws.policyNameto its name. The template attaches it to the workload’s identity.
GCS
- Create a GCS bucket. Set
backup.gcp.bucketto its name. - Create a Control Plane Cloud Account for the GCP project holding the bucket, granting its service account the Storage Admin role. Set
backup.gcp.cloudAccountNameto its name. The template bindsroles/storage.objectAdminon exactly that bucket.
One-off dump
For an ad-hoc dump without the backup job, runmysqldump inside the database container and stream it out. The container already holds the root password and the database name as environment variables, and the stream is base64-encoded on both sides because cpln workload exec does not pass binary data through intact:
Restoring a Backup
The database is not reachable from the internet, so the dump is loaded from inside the database container. Themysql:9 image ships mysql, gunzip and base64, and the container holds the root password as MYSQL_ROOT_PASSWORD, so you never type it.
Download the dump
Stream it into the running server
--stdin is required — without it the piped file is silently discarded and nothing is restored. No database name is passed because the dump was taken with --databases, so it carries its own CREATE DATABASE IF NOT EXISTS and USE statements. Each table in the dump is dropped and recreated; tables that exist on the server but not in the dump are left alone.Verify
mysql:9 image. It has not been exercised against a live install of this template version.Upgrading from 1.5.0
Version 1.5.1 removes theaws::ReadOnlyAccess managed policy from the backup identity. That policy granted read access to every bucket in your AWS account and contains no write actions, so it never carried the backup itself — but it was silently supplying any read action your own bucket-scoped policy happened to omit.
Update your IAM policy to the full ten-action list under Backing Up before upgrading. If it already matches, no action is needed. The identity now carries cpln-connector and your bucket-scoped policy only. Nothing else changes.
Upgrading from 1.4.3 or Earlier
Template versions up to 1.4.3 took the database credentials as plain Helm values with working defaults, and deployed phpMyAdmin enabled and reachable from the entire internet. Version 1.5.0 removed both.Read the credentials the database already uses
user, password, database and rootPassword.Create the two prerequisite secrets with those same values
Remove the old keys from your values
config block and enablePhpMyAdmin, then set credentialsSecretName and rootPasswordSecretName to the two secret names. If you were using the console, add phpMyAdmin.enabled: true — it is off by default now, and internal-only unless you also set phpMyAdmin.publicAccess.enabled: true.Upgrade, then rotate the passwords
root for both localhost and %, so rotating root means changing both. Use your own username in place of appuser.Scaling and Availability
This is a single instance on a single volume. The chart pins the workload to exactly one replica (minScale and maxScale of 1), and there is no replication or clustering mode — do not raise the replica count. Scale vertically with resources, and let the volume grow with volumeset.autoscaling.
Data lives on the volume set and survives restarts, redeploys and cpln helm upgrade. cpln helm uninstall deletes the volume set and the database with it; take a backup first.
Troubleshooting
The workload never becomes ready and cpln logs returns nothing
The workload never becomes ready and cpln logs returns nothing
cpln helm install succeeded, RELEASE_NAME-mysql never reaches ready, and cpln logs returns zero lines. cpln workload get RELEASE_NAME-mysql --gvc GVC_NAME shows a tag of the form cpln/secret:SECRET_NAME: secret-does-not-exist.Cause: one of the two prerequisite secrets does not exist, so the container cannot start. The missing secret is named in status.versions[].message:helm upgrade fails with 'the config block was removed in 1.5.0'
helm upgrade fails with 'the config block was removed in 1.5.0'
cpln helm upgrade stops before touching any resource with one of:Access denied after changing a secret
Access denied after changing a secret
CREDENTIALS_SECRET_NAME or ROOT_SECRET_NAME (and redeploying), connections fail with:root) fails too and the workload stops reporting ready.Fix: put the old value back in the secret, then rotate inside MySQL and update the secret afterwards:root, change both 'root'@'localhost' and 'root'@'%'. To start over with a fresh database instead, cpln helm uninstall (which deletes the volume set and all data) and reinstall.The backup job runs but nothing appears in the bucket
The backup job runs but nothing appears in the bucket
RELEASE_NAME-mysql-backup runs on schedule and its logs end with an upload error such as:backup.aws.policyName is missing actions (common after upgrading from 1.5.0), or the Cloud Account does not cover the account or project holding the bucket.Fix: make the IAM policy match the ten-action list under Backing Up and confirm backup.aws.bucket / backup.gcp.bucket and the Cloud Account name are correct. The next scheduled run picks up the change.Important Notes
- Create both prerequisite secrets before installing. A reference to a secret that does not exist wedges the workload instead of failing the install.
- Credentials are applied only when the volume is first initialized. Rotating a secret afterwards does not change the stored passwords — use
ALTER USERinside MySQL and update the secret to match. - Do not scale past one replica. This is a single instance on a single volume, not a replicated cluster.
cpln helm uninstalldeletes the volume set and the database with it. Take a backup first.- Access changes take a few minutes to apply after an
internalAccessorpublicAccesschange — a connection attempt made immediately afterwards is not evidence the knob is broken. - Upgrading from 1.4.3 or earlier is a breaking change — the removed keys stop the upgrade rather than resetting a password. See Upgrading from 1.4.3 or Earlier.