Skip to content

Rate this page
Thanks for your feedback
Thank you! The feedback has been submitted.

Get free database assistance or contact our experts for personalized support.

Users

MySQL user accounts within the Cluster can be divided into two different groups:

  • application-level users: the unprivileged user accounts,
  • system-level users: the accounts needed to automate the cluster deployment and management tasks, such as Percona Server for MySQL Health checks.

As these two groups of user accounts serve different purposes, they are considered separately in the following sections.

Unprivileged users

The Operator doesn’t create application-level (unprivileged) user accounts by default.

You can create these unprivileged users in the following ways:

Create users in the Custom Resource

!!! admonition “Version added: 1.3.0

You can create users in Percona Server for MySQL via the spec.users subsection in the Custom Resource. This is called declarative user management.

You can change the spec.users section in the deploy/cr.yaml configuration file either at cluster creation time or adjust it later. For each user, you can specify:

  • The user’s login name. Required.
  • Hosts this user is allowed to connect from
  • Databases the user can access. If a database you list does not exist, the Operator creates it
  • MySQL privilege grants
  • A reference to a Secret resource containing the user’s password if you created the password manually. Otherwise, the Operator generates the password and creates the Secret for the user named <cluster-name>-user-<username>. See Passwords generated by the Operator.

Here is an example configuration of the Custom Resource:

spec:
  users:
    - dbs:
        - mydb
      grants:
        - SELECT
        - INSERT
      hosts: []
      name: alice
      passwordSecretRef:
        key: password
        name: alice-secret
      withGrantOption: false
    - dbs:
        - mydb
      grants:
        - SELECT
        - INSERT
      hosts: []
      name: bob
      withGrantOption: true

For detailed information about all available options, see the Custom Resource reference.

The Operator applies custom users after the cluster reaches the ready state.

Generate user passwords manually

You can create the Secret containing the user password yourself and reference it in the users.passwordSecretRef.name option in the Custom Resource. The Secret should follow this format:

apiVersion: v1
kind: Secret
metadata:
  name: my-user-pwd
type: Opaque
stringData:
  password: my-user-password

The Operator tracks password changes in the Secret object and automatically updates the user password in the database when the Secret is modified.

User passwords generated by the Operator

If you omit passwordSecretRef, the Operator generates a password and stores it in a Secret named <cluster-name>-user-<username>. For a cluster named ps-cluster1 and a user named alice, the Secret is ps-cluster1-user-alice. The password is stored under the password key.

If the username is not a valid Kubernetes Secret name, the Operator sanitizes it and appends a hash so the Secret name remains valid.

Generated passwords use the same character set and length (16–20 characters) as system user passwords.

Important considerations

When creating users via the Custom Resource, keep the following behavior in mind:

  • Minimal configuration: The only required field is users.name. If you omit other fields:

    • If no Secret is specified, the Operator generates a password and stores it in <cluster-name>-user-<username>
    • If hosts is omitted, the user can connect from any host (%)
    • If dbs is omitted and you set grants, those grants apply to all databases (*.*)
    • If grants is omitted, the Operator creates the user without additional GRANT statements. MySQL then provides the default USAGE privilege
  • Reserved names: You cannot use a system user name (root, operator, monitor, xtrabackup, replication, orchestrator, heartbeat, clusterset, configurator, or pmmservertoken). The Operator skips such entries.

  • User deletion: The Operator does not delete users when you remove them from the Custom Resource. This prevents accidental removal of accounts that may also exist outside the Operator. Drop users in MySQL yourself if you no longer need them. If you drop a user directly in MySQL, the Operator recreates it only after that user’s spec or password Secret changes.
  • Host changes: When you update the hosts array (for example, changing host1 to host2), the Operator creates a new account user@host2 and leaves user@host1 in place. Password rotation applies only to the hosts currently listed in the Custom Resource. If you later change the host back to host1, that original account keeps its previous password, which may differ from the password in the Secret.
  • Grant updates: The Operator updates grants in an additive manner. It adds new grants but does not revoke existing ones that are not specified in the Custom Resource.
  • Duplicate users: User names in spec.users must be unique. You cannot define two entries for the same user (for example, with different grants for different databases) in a single Custom Resource. You can achieve this by making sequential updates to the Custom Resource.
  • Invalid grants: Grant strings cannot be empty and cannot contain ,, ;, ', ", `, or \. If validation fails, the Operator does not create that user. If a grant is valid syntactically but MySQL rejects it (for example, an administrative privilege such as SHUTDOWN together with dbs), the Operator logs an error. In that case the account may already exist with default grants (USAGE) because CREATE USER runs before GRANT.
  • Administrative privileges: Privileges that apply only at the global level (such as SHUTDOWN) require you to omit dbs. If you set dbs, the Operator issues GRANT ... ON <database>.*, which MySQL rejects for those privileges.
  • Internal Secret: The Operator also maintains a Secret named <cluster-name>-internal-custom-users for its own tracking. Do not edit this Secret.

Create users manually

Instead of using the Custom Resource, you can create unprivileged users directly in MySQL using standard SQL commands. This approach gives you full control over user creation and is useful when you need configurations that the Custom Resource does not express.

Start a temporary Percona MySQL client Pod and connect to MySQL in your cluster:

kubectl run -it --rm percona-client --image=percona:8.4 --restart=Never -- mysql -hps-cluster1-mysql -uroot -proot_password

The following SQL command creates a new user user1 with the password password1, and grants this user all privileges on all tables in the database1 database. The @'%' means that the user can connect from any host.

CREATE USER 'user1'@'%' IDENTIFIED BY 'password1';
GRANT ALL PRIVILEGES ON database1.* TO 'user1'@'%';
FLUSH PRIVILEGES;

Note

MySQL password here should not exceed 32 characters due to the replication-specific limit introduced in MySQL 5.7.5 .

Verify that the user was created successfully. If successful, the following command will let you successfully login to MySQL shell:

kubectl run -it --rm percona-client --image=percona:8.4 --restart=Never -- bash -il
percona-client:/$ mysql -h ps-cluster1-mysql-primary -uuser1 -ppassword1
mysql> SELECT * FROM database1.table1 LIMIT 1;

You may also try executing any simple SQL statement to ensure the permissions have been successfully granted.

Connection secrets

For the root user, the Operator creates a Secret named <cluster_name>-psuser-root that contains ready-to-use connection details: hostname, port, username, password, connection URIs, and proxy endpoints. The Operator updates this Secret automatically when the primary changes or when proxy configuration changes.

For example, the root user on a cluster named ps-cluster1 gets a Secret called ps-cluster1-psuser-root. Application Pods can mount this Secret directly instead of assembling connection parameters manually.

See Connection secrets for the full field reference, read-only connection guidance, and application integration examples.

System Users

To automate the deployment and management of the cluster components, the Operator requires system-level Percona Server for MySQL users.

Credentials for these users are stored as a Kubernetes Secrets object. The Operator requires to be deployed before the Percona Server for MySQL is started.

Note

The Operator will either use existing Secrets, or create a new Secrets object with randomly generated passwords if it didn’t exist. Also, starting from the Operator version 0.5, it will generate random passwords for system users not found in the existing Secrets object.

The name of the required Secrets (ps-cluster1-secrets by default) should be set in the spec.secretsName option of the deploy/cr.yaml configuration file.

The following table shows system users’ names and purposes.

Warning

These users should not be used to run an application.

User Purpose Username Password Secret Key Description
Admin root root Database administrative user, can be used by the application if needed
Orchestrator orchestrator orchestrator Orchestrator administrative user and credentials for read/write access to the Orchestrator HTTP API (from Operator version 1.2.0 when spec.crVersion is 1.2.0 or higher)
Backup xtrabackup xtrabackup User to run backups
Cluster Check clustercheck clustercheck User for liveness checks and readiness checks
Monitoring monitor monitor User for internal monitoring purposes and PMM agent
Operator Admin operator operator Database administrative user, should be used only by the Operator
Replication replication replication Administrative user needed for replication
ClusterSet clusterset clusterset Administrative user for InnoDB ClusterSet AdminAPI operations and cross-site replication; should be used only by the Operator’s ClusterSet controller
PMM Server token pmmservertoken The service token used to access PMM Server

Orchestrator HTTP API authentication

Starting with Operator version 1.2.0, the Orchestrator HTTP API on port 3000 requires authentication when spec.crVersion is 1.2.0 or higher. This applies to asynchronous replication clusters where Orchestrator manages failover and topology.

The Operator authenticates its own API calls automatically using the orchestrator system user from the cluster Secret. You do not need to configure anything for normal cluster operation.

If you call the Orchestrator API yourself (for example from a custom script or when Orchestrator is exposed outside the cluster), use one of the following:

  • orchestrator user — read and write access. Use the password stored under the orchestrator key in the cluster Secret (spec.secretsName).
  • readonly user — read-only access. Orchestrator accepts any password for this built-in user.

Unauthenticated requests receive HTTP 401. Upgrading the Operator alone does not enable API authentication on existing clusters; set spec.crVersion to 1.2.0 or higher to activate it.

YAML Object Format

The default name of the Secrets object for these users is ps-cluster1-secrets and can be set in the CR for your cluster in spec.secretName to something different. When you create the object yourself, it should match the following simple format:

apiVersion: v1
kind: Secret
metadata:
  name: ps-cluster1-secrets
type: Opaque
stringData:
  root: root_password
  xtrabackup: backup_password
  monitor: monitor_password
  pmmserverkey: my_pmm_server_key
  operator: operator_password
  replication: replication_password
  clusterset: clusterset_password
  orchestrator: orchestrator_password
  heartbeat: heartbeat_password

As you can see, because we use the stringData type when creating the Secrets object, all values for each key/value pair are stated in plain text format convenient from the user’s point of view. But the resulting Secrets object contains passwords stored as data - i.e., base64-encoded strings. If you want to update any field, you’ll need to encode the value into base64 format. To do this, you can run echo -n "password" | base64 --wrap=0 (or just echo -n "password" | base64 in case of Apple macOS) in your local shell to get valid values. For example, setting the Admin user’s password to new_password in the ps-cluster1-secrets object can be done with the following command:

kubectl patch secret/ps-cluster1-secrets -p '{"data":{"root": "'$(echo -n new_password | base64 --wrap=0)'"}}'
kubectl patch secret/ps-cluster1-secrets -p '{"data":{"root": "'$(echo -n new_password | base64)'"}}'

Password rotation policies and timing

When there is a change in user secrets, the Operator creates the necessary transaction to change passwords. This rotation happens almost instantly (the delay can be up to a few seconds), and it’s not needed to take any action beyond changing the password.

Warning

Please don’t change secretName option in CR, make changes inside the secrets object itself.

Passwords with special characters

The Operator automatically generates passwords for user secrets with special characters to increase security. It uses the following set of characters:

  • Uppercase letters (A–Z)
  • Lowercase letters (a–z)
  • Digits (0–9)
  • Special symbols: ! $ % & ( ) * + , - . < = > ? @ [ ] ^ _ { } ~ #

This character set has been carefully selected to ensure correct functioning of SQL, shell scripts, YAML files and connection strings.

To avoid issues in these contexts, the following characters are excluded: single quotes (‘), double quotes (“), backslashes (), forward slashes (/), colons (:), pipes (|), semicolons (;) and backticks (`).

You can define passwords for user secrets yourself. When doing so, be sure to stick to the approved character set to ensure your services run smoothly.

Marking System Users In MySQL

Starting with MySQL 8.0.16, a new feature called Account Categories has been implemented, which allows us to mark our system users as such. See the official documentation on this feature for more details.


Last update: August 21, 2026
Created: August 21, 2026