MySQL Version Upgrades
This page covers upgrading the MySQL server version of a running cluster, distinct from upgrading the operator itself (see Operator Upgrades).
Supported transitions​
MySQL only supports upgrades between adjacent release series, and never a downgrade in place. cnmsql enforces the same chain:
8.0 → 8.4 → 9.0
- You must move one series at a time.
8.0 → 9.0directly is rejected; go8.0 → 8.4, then8.4 → 9.0. - Patch upgrades within a series (e.g.
8.0.36 → 8.0.40) are unrestricted. - Downgrades are not supported. Once a server starts on the new series it upgrades its data dictionary, which is irreversible. The only way back is to restore a backup taken before the upgrade (see Rollback).
The supported chain lives in UpgradeSeriesChain
(pkg/management/mysql/version/version.go) and is enforced in two places:
- Admission:
Cluster.ValidateUpdaterejects a downgrade, a skipped series, or a series change expressed throughimageNameinstead of a catalog. - The instance manager: before starting mysqld, it compares the series recorded in the data directory against the image version and refuses to start on an unsupported transition, even if admission was bypassed.
How to upgrade​
Major upgrades must be driven through an ImageCatalog (or
ClusterImageCatalog), so the target series is explicit. The catalog is keyed by
series (8.0, 8.4, 9.0), not by integer major. 8.0 and 8.4 are distinct
upgrade targets.
-
Ensure the catalog lists the target series:
apiVersion: mysql.cnmsql.co/v1alpha1kind: ImageCatalogmetadata:name: percona-imagesspec:images:- series: "8.0"image: ghcr.io/cnmsql/cnmsql-instance:8.0- series: "8.4"image: ghcr.io/cnmsql/cnmsql-instance:8.4 -
Point the cluster at the next series:
spec:imageCatalogRef:apiGroup: mysql.cnmsql.cokind: ImageCatalogname: percona-imagesseries: "8.4" # was "8.0" -
Apply. The operator first takes a pre-upgrade backup (see below), then rolls instances one at a time, replicas first and the primary last (the primary via switchover where a healthy replica exists), so only one instance is down at a time and a newer replica never replicates from an older primary. Each instance must become Ready, which, with the default
--upgrade=AUTO, means its data-dictionary upgrade has finished, before the next one rolls.
Pre-upgrade backup gate​
Because the data-dictionary upgrade is irreversible, the operator takes a fresh
backup before rolling any instance and waits for it to complete. This is
controlled by spec.upgrade.backupBeforeUpgrade (default true):
spec:
upgrade:
backupBeforeUpgrade: true # default; set false to skip
If it is enabled but no spec.backup.objectStore is configured, the upgrade is
blocked (status phase Blocked, event BackupRequired) rather than rolling
unprotected. Configure a backup destination or set backupBeforeUpgrade: false
(e.g. when an external backup process is in place).
Group Replication​
During a Group Replication upgrade, the group continues using its old
communication protocol while members roll. Once every member reports the target
series and is ONLINE, the operator automatically calls
group_replication_set_communication_protocol on the primary with the full
target version. The action is idempotent and the cluster briefly reports phase
Upgrading while the protocol is finalized. Cluster status records both the
effective communicationProtocol and the requested
communicationProtocolTarget. These can differ: MySQL 8.4 uses the effective
protocol 8.0.27 even when finalized with an 8.4 server target.
Rollback​
There is no in-place downgrade. To return to the previous series:
- Provision a new cluster (or recover into one) on the old series.
- Bootstrap it from the backup taken before the upgrade
using
bootstrap.recovery.
A backup taken after the upgrade has already-upgraded data and cannot restore the old series.
Troubleshooting​
- The update is rejected on apply. Admission refused the transition. Check the
message: a skipped series (
upgrade to 8.4 first), a downgrade, or a series change viaimageName(useimageCatalogRefinstead). - A Pod crash-loops right after the image change. The instance manager refused
an unsupported transition (the data directory's series does not match the
image). The reason is in the Pod log:
Refusing to start mysqld: unsupported MySQL version transition. Reconcile the catalog/series so the hop is a single forward step. - mysqld fails to start citing an "unknown variable". A user-supplied
spec.mysql.parametersvalue was removed in the target series. The operator drops known-removed variables automatically and emits aRemovedParameterwarning event; for anything it does not yet know about, remove the offending variable from the spec. Common removals in 8.4 includedefault_authentication_plugin,expire_logs_days, andmaster_info_repository. - The upgrade is blocked on a backup. The cluster status phase is
Blockedwith aBackupRequiredevent:backupBeforeUpgradeis enabled (the default) but nospec.backup.objectStoreis configured. Configure a destination, or setspec.upgrade.backupBeforeUpgrade: false. While the pre-upgrade backup runs the phase isUpgradingwith a "Waiting for pre-upgrade backup" reason. - The rollout stalls part-way. The operator serializes the roll and waits for each instance to become Ready before the next. Inspect the cluster status phase and the per-instance logs to find the instance that is not becoming Ready.
- All GR members upgraded but the protocol did not advance. Confirm every
member is
ONLINEand reports the target server series, then inspect the primary instance-manager log forFinalizing group communication protocolor a failed/group/set-communication-protocolaction. From MySQL, comparegroup_replication_get_communication_protocol()withstatus.groupReplication.communicationProtocol, and check thatcommunicationProtocolTargetmatches the upgraded server series. The operator retries on later reconciles once status is complete and healthy.