Sep
09
2026
--

Percona Operator for PostgreSQL 3.1.0: Transparent Data Encryption, Logical Replicas, and Persistent Logging

Percona Operator for PostgreSQL 3.1.0 takes on three things that decide whether a PostgreSQL platform passes review: is the data encrypted at rest, can it serve reads without straining the primary, and are the logs there when you need them. This release answers all three inside the custom resource, so none of them is a bolt-on you maintain yourself.

The three headline features are transparent data encryption with pg_tde, logical replicas, and persistent logging. pg_tde encrypts your data on disk, including the write-ahead log. Logical replicas add a read-only copy inside the cluster for reporting and analytics. Persistent logging keeps PostgreSQL and pgBackRest logs across Pod restarts.

The operator is open source and runs on any CNCF-certified Kubernetes distribution. This release also widens where it runs, adding official Rancher Kubernetes Engine (RKE2) support and full ARM64 images. Much of what shipped here comes from requests on forums.percona.com and the public issue tracker.

In this post, you’ll learn about:

  • Transparent data encryption with pg_tde
  • Logical replicas for read-only workloads
  • Persistent logging for PostgreSQL and pgBackRest
  • Other improvements worth knowing about

 

Transparent data encryption with pg_tde

Encryption at rest is usually the line item that blocks a database from going into a regulated environment. Storage-level encryption from the cloud provider covers the disk, but it does not protect a copied volume, a leaked backup, or a stray WAL segment, and auditors increasingly want encryption the database itself controls. This release adds transparent data encryption through pg_tde, Percona’s open source TDE extension for PostgreSQL.

 

Why it matters

With pg_tde, the data in tables, indexes, temporary tables, and the write-ahead log stays encrypted on disk, and PostgreSQL decrypts it only in memory for a session that holds the key. That closes the gaps storage encryption leaves open: a snapshot of the volume, a backup shipped to object storage, or a WAL file replicated off-node is ciphertext without the key. Because the key lives in an external provider rather than next to the data, you separate who runs the database from who controls the keys. In practice this is what lets a team bring PostgreSQL on Kubernetes into scope for a standard like PCI DSS or HIPAA without moving the workload off the platform: the encryption the auditor asks about lives in the database, and key custody lives in Vault under a different team’s control.

 

How it works

The operator wires pg_tde to HashiCorp Vault as the key provider. You enable the extension in the custom resource and point it at your Vault instance and a token Secret. The operator handles loading the extension and configuring the key set on the PostgreSQL instances. WAL encryption is a separate switch, so you can encrypt table data and the write-ahead log together. pg_tde uses a two-tier key model: a principal key in Vault wraps the internal data keys, so rotating the principal key is a key-management operation in Vault rather than a full re-encryption of the database.


Wiring it up

apiVersion: pgv2.percona.com/v2
kind: PerconaPGCluster
metadata:
  name: cluster1
spec:
  extensions:
    pg_tde:
      enabled: true
      walEncryption: true
      vault:
        host: https://vault-service:8200
        mountPath: tde
        tokenSecret:
          name: pg-tde-vault-secret
          key: token
        caSecret:
          name: pg-tde-vault-secret
          key: ca.crt

 

enabled: true loads pg_tde and turns on encryption for the cluster, and walEncryption: true extends it to the write-ahead log. The vault block points at your key provider: host and mountPath locate the secrets engine, tokenSecret holds the Vault token, and caSecret carries the CA certificate so the operator trusts the Vault endpoint. Keep the Vault token and CA in Kubernetes Secrets, not in the manifest.

 

Note: pg_tde in 3.1.0 is available for PostgreSQL 17 and 18. Encryption applies to data written after you enable it, so plan enablement as part of provisioning a cluster rather than as a switch on a full production database.


Logical replicas for read-only workloads

 

A PostgreSQL cluster under the operator is a primary with streaming physical replicas that Patroni manages for high availability. Those replicas exist to take over on failover, not to be a stable place to point a reporting tool, because their role can change at any time. Teams that want a durable read endpoint for analytics have had to run a second cluster or wire up replication by hand. This release adds a logical replica you declare inside the same cluster.

 

Why it matters

Reporting and analytics queries have a different shape than transactional traffic: they scan more, run longer, and arrive in bursts when a dashboard refreshes or a nightly job starts. Pointed at the primary, they compete with the writes that keep the application responsive. A logical replica gives that traffic its own copy and its own compute, so a heavy analytics query slows down a chart, not a checkout. Because the endpoint is stable, you set the reporting tool’s connection string once and leave it.


How it works

A logical replica is a read-only copy with its own volume and its own Service, seeded from a pgBackRest backup and kept current through logical replication. Patroni does not manage it, so it never gets promoted and its endpoint stays stable: a reporting query or a dashboard can point at it and stay pointed at it. You can target specific databases or replicate all of them, and size the replica independently of the primary.


Wiring it up

spec:
  logicalReplicas:
  - name: analytics
    databases: []  # empty = all non-template databases except "postgres"
    bootstrapMethod: pgbackrest
    dataVolumeClaimSpec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 1Gi
    resources:
      limits:
        cpu: 2.0
        memory: 4Gi
    expose:
      type: LoadBalancer


name
becomes the replica’s identity and the basis for its Service. databases selects what to replicate, where an empty list means every non-template database except postgres. bootstrapMethod: pgbackrest seeds the replica from a backup rather than from the live primary, which keeps the initial sync off the primary’s back. dataVolumeClaimSpec and resources size it for the read workload, and expose publishes the read endpoint.

 

Note: Logical replicas are a tech preview in 3.1.0 and require PostgreSQL 17 or later. Logical replication does not copy schema changes automatically, so treat DDL on the primary as something you coordinate with the replica.

 

Persistent logging for PostgreSQL and pgBackRest

Logs matter most right after something goes wrong, which is exactly when a Pod is most likely to have restarted and taken its logs with it. When PostgreSQL logs only to a container’s stdout, a crash-loop or a reschedule erases the evidence you need to explain it. The classic case is a crash-looping instance: by the time you exec into a fresh Pod, the stdout from the crash is gone, but an on-disk log still holds the panic and the queries around it. This release keeps PostgreSQL and pgBackRest logs on the instance data volume, so they survive Pod restarts.

 

How it works

The operator runs a Fluent Bit log collector as a sidecar that reads the on-disk logs and emits them as structured JSON lines. Because the logs live on the data volume, they persist across restarts and rescheduling. From there you can forward them off-cluster: the collector can ship to S3 or over OpenTelemetry to whatever aggregation stack you already run, configured through the custom resource. The same on-disk logs that help you debug an incident become the audit trail your security team retains, without a second logging agent to install.


Wiring it up

spec:
  logcollector:
    enabled: true
    image: docker.io/perconalab/fluentbit:main-logcollector
#    configuration: |
#      pipeline:
#        filters:
#          - name: record_modifier
#            match: "*"
#            record:
#              - cluster_name cluster1

 

enabled: true turns on the Fluent Bit collector, and image pins the collector build. The commented configuration block is a Fluent Bit pipeline you can supply to filter, enrich, or route logs: the example tags every record with a cluster_name, and the same mechanism adds an output to forward logs to S3 or an OpenTelemetry endpoint. You can also tune log rotation so retention matches your operational windows and compliance rules.

 

Note: Persistent logs consume space on the instance data volume. Set a rotation policy that fits the volume so logs do not compete with the database for storage.

 

Other improvements

Beyond the three headline features, 3.1.0 ships a set of enhancements that smooth day-two operations:

  • Community PostgreSQL images and custom registries (K8SPG-1056): run Percona Distribution for PostgreSQL, community PostgreSQL, or your own images by setting spec.image, proxy.pgBouncer.image, and spec.backups.pgbackrest.image.
  • Auto-growable pgBackRest disks (K8SPG-691): let backup repository volumes grow to a limit instead of filling up and failing a backup.
  • Pause and resume pgBouncer (K8SPG-1115): set proxy.pgBouncer.paused to hold client traffic without dropping application connections.
  • mTLS for pgBouncer (K8SPG-952): extend the pgBouncer trust bundle with your external CA through proxy.pgBouncer.additionalTrustedCAs while the operator keeps rotating cluster TLS.
  • cert-manager Issuer and TLS policy (K8SPG-951, K8SPG-1045): point the operator at your own Issuer, and use certManagementPolicy to decide who owns certificate lifecycle.
  • Extra volume mounts (K8SPG-440): mount extra ConfigMap, Secret, PVC, or emptyDir volumes into the PostgreSQL container through instances.extraVolumes.
  • pg_cron and set_user are now built-in (K8SPG-1040): enable them through extensions without supplying a custom build.
  • PostgreSQL 19 tech preview (K8SPG-1051) and full ARM64 support (K8SPG-881): evaluate the next major early, and run the operator natively on ARM.

One deprecation to plan for: this release removes PMM2 support (K8SPG-944), so move monitoring to PMM3. The extensions.builtin field is deprecated in favor of extensions.<name>.enabled; migrate before 3.4.0.

 

Conclusion

Percona Operator for PostgreSQL 3.1.0 tightens the parts of a PostgreSQL platform that reviews and on-call rotations care about most: pg_tde encrypts data at rest under keys you control, logical replicas give analytics a stable read endpoint without a second cluster, and persistent logging keeps the evidence when a Pod restarts. With RKE2 and full ARM64 support, more of that runs on the platforms teams actually use. If there is a workflow you still script around the operator, tell us on the forum, since that is where releases like this one come from.


Try Percona Operator for PostgreSQL 3.1.0

 

 

The post Percona Operator for PostgreSQL 3.1.0: Transparent Data Encryption, Logical Replicas, and Persistent Logging appeared first on Percona.

Sep
02
2026
--

OpenID Connect Authentication for MySQL, Now Fully Open Source

Percona Server for MySQL now ships with a fully open source OpenID Connect (OIDC) authentication plugin, available starting with Percona Server for MySQL 8.4.11-11 and 9.7.2-2 (not yet released as of this writing). It allows a MySQL account to authenticate against any standards-compliant Identity Provider (IdP) instead of relying on a locally stored password, closing the gap with MySQL Enterprise Edition, which has offered OIDC authentication since MySQL 9.1 and, in several respects, going beyond it.

Oracle offers the same category of functionality, but its server-side plugin is part of the paid MySQL Enterprise Edition. Percona’s implementation is open source and adds three capabilities the Enterprise plugin does not provide: automatic signing-key synchronization from a JWKS endpoint, IdP group-to-role mapping, and proxy-user support. This article explains how the plugin works and why those differences matter in practice.

What OpenID Connect Brings to MySQL Authentication

OpenID Connect is an identity layer built on top of the OAuth 2.0 authorization framework [5]. Whereas OAuth 2.0 governs delegated access to resources, OIDC adds a standardized way for a client to establish who a user is. After a user signs in to an Identity Provider, the IdP issues a signed JSON Web Token (JWT), called an ID token, that carries the user’s identity and attributes in a verifiable, tamper-evident form.

Using that model for MySQL authentication brings several practical advantages over password-based accounts:

  • Alignment with single sign-on. Users authenticate once with their IdP and can reuse that session context across OIDC-aware applications, including databases. User lifecycle and password management remain centralized.
  • No long-lived secrets on the wire. ID tokens are short-lived and cryptographically signed, so there is no static password to steal, rotate, or accidentally commit to a configuration file.
  • Support for hybrid deployments. Organizations that run MySQL on-premises while hosting applications in the cloud can still authenticate through the same identity plane on both sides.
  • Broad interoperability. Because OpenID Connect is a widely adopted standard, the plugin can work with any compliant provider, including Keycloak, Okta, Microsoft Entra ID, and Google Identity.

None of that is unique to Percona; Oracle makes a similar value proposition for the Enterprise plugin. The real difference lies in how much operational burden the plugin removes from the administrator, which becomes clear in the next sections.

How OpenID Connect Authentication Works

Once the plugin and its configuration are in place, the authentication path is the same regardless of which IdP issued the token:

  1. The user authenticates to the IdP and receives a signed ID token.
  2. The token is written to a local file that only the client operating system account can read.
  3. The MySQL client uses an option that causes the client-side OIDC plugin to load and read the token from the file. The token is sent to the server as part of the authentication handshake.
  4. The server validates the secure channel and decodes the token. It then verifies the token signature using the selected IdP’s public key, checks the expiration time, and validates the configured claims.
  5. The server resolves the final identity as either a personal account or a group-based proxy target. The plugin may also return roles mapped from the user’s group membership.

Configuring Trusted Providers and Letting the Plugin Manage the Keys

Identity Providers rotate their signing keys periodically as a basic security measure. If a key is ever compromised, limiting its lifetime reduces the potential impact, and regular rotation also lowers the long-term value of any one key as a target. In practice, rotation is gradual: a new key is published and accepted before it starts signing tokens, and an old key remains valid for a period after it stops signing so that tokens already in flight can still be verified.

Public keys are exposed through the standard JWKS (JSON Web Key Set) endpoint, which applications can use to verify tokens issued by the IdP [6].

The Percona OpenID Connect authentication plugin can download public keys from a configured JWKS endpoint when the plugin is loaded, typically during installation and server startup, and store them in a cache. It also provides a User Defined Function (UDF) that can refresh the cache on demand or periodically through the Event Scheduler.

By contrast, Oracle’s counterpart plugin requires signing keys to be configured statically through the authentication_openid_connect_configuration server variable, supplied either as an inline JSON string or as a path to a JSON file. There is no retrieval or refresh from the JWKS endpoint, so keeping keys current after each rotation remains a manual task for the administrator. In the window just after a rotation, tokens signed with the previous key are still valid but cannot be verified until the configuration is updated. Percona’s plugin supports static key configuration as well, but that mode is better suited to testing or temporary setups than to production.

Example

Using the feature requires two simple steps. First, JWKS endpoint URL must be set in the plugin’s configuration. For example, the below configuration defines IdP named as example-keycloak (pay attention to jwks-url element):

{
  "example-keycloak": {
  "issuer-name": "https://keycloak.example.com/realms/master",
  "jwks-url": "https://keycloak.example.com/realms/master/protocol/openid-connect/certs",
  "audiences": [ "mysql-oidc" ]
  }
}

The second step is ensuring the MySQL event scheduler is running and creating an event updating the keys. For example, to enable updating the keys for example-keycloak every hour run from MySQL client:

CREATE EVENT update_oidc_keys
  ON SCHEDULE EVERY 1 HOUR
  DO SELECT update_jwks("example-keycloak");

Benefits of Using IdP Groups

This is where Percona’s plugin diverges most clearly from the Enterprise implementation.

Groups are managed by the corporate Identity Provider and group membership may be carried by ID tokens. OIDC does not define a standard claim for that, but most IdP implementations allow adding a group claim to the tokens. The Percona’s plugin allows the administrator to configure the group claim name so that it matches the token format used by the chosen IdP.

There are two practical ways to take advantage of this feature:  group-to-role mapping and proxy users.

Group-to-Role Mapping

Membership in a group can automatically translate into MySQL roles and therefore privileges across multiple MySQL servers at the same time. On a single server, the flow looks like this:

  1. The administrator creates roles and grants them privileges.
  2. The administrator defines the IdP group-to-MySQL role mapping in the plugin configuration file.
  3. When the user connects, the plugin returns the roles that match the user’s groups, and the server automatically grants those roles to the user.
  4. The user can activate any granted role and exercise the privileges assigned to it.

Please note, that group-to-role mapping still requires an account created for each user, but automates managing user privileges.

Example

To create roles and grant them some privileges one may run:

CREATE ROLE accounting;
GRANT ALL PRIVILEGES ON accounting_database.* TO accounting;
CREATE ROLE sales;
GRANT ALL PRIVILEGES ON sales_database.* TO sales;

Then, to to define the mapping add to IDP configuration:

"group-claim": "groups",
"group-role": [
  { "/accounting": "accounting" },
  { "/marketing": "marketing" }
]

Any user connecting with an ID token containing claim “groups”:[“/accounting”] will be granted with role accounting and effectively obtain access to accounting_database and so on.

Proxy Users

The proxy capability in MySQL allows an authentication plugin to request that the connecting external user be logged in as a different MySQL user. In this model, the external identity is the proxy user and the mapped MySQL account is the proxied user. The purpose is to let multiple users share accounts with the same privilege set, avoiding the need to create a separate personal database account for every individual.

This feature must be supported by the authentication plugin, whose job is to choose the proxied user according to the specifics of the authentication method. In the Percona OIDC plugin, that selection is based on the group claim in the token and works as follows:

  1. The administrator creates a proxy user identified by the OIDC plugin. This can be either a single anonymous account (”@”) without a specific group name, referred to as anonymous proxying, or multiple group-related accounts, referred to as named group proxying.
  2. The administrator creates proxied users for each group. These accounts should not use a login plugin, so nobody can connect to them directly. The username must match the group name.
  3. The administrator grants the PROXY privilege for each proxy user on all related proxied users.
  4. When a user connects, in the anonymous proxying case the plugin returns the user’s first group as the proxied username. In the named group proxying case, the plugin checks whether the user belongs to the group and returns that group as the proxied username.
  5. The server verifies that the requested proxied account exists and that the proxy user has the required PROXY privilege on it. If both checks succeed, the session runs with the proxied account’s privileges.

Other Features

Supported signing algorithms include RSASSA-PKCS1-v1_5, RSASSA-PSS, and ECDSA with SHA-256, SHA-384, and SHA-512 hashing functions.

The Percona approach uses the client-side OpenID Connect plugin from upstream MySQL, which ensures compatibility with the standard Oracle client.

Both client-side and server-side OpenID Connect plugins ensure that the token is sent via a secure channel. Accepted protocols are TCP protected by TLS, Unix sockets, and shared memory.

What OpenID Connect Authentication Does Not Do

There are some limits worth knowing.

The first comes from MySQL’s authentication design: any authentication plugin is used at connection time only. In the case of OIDC, the token is validated when the user connects, and a session that stays open may outlive the ID token that opened it. There is no out-of-the-box mechanism to force re-authentication after some time (except for idle connection timeout).

A similar situation applies to group-role mapping. The roles tied to the user’s groups in the ID token are granted or revoked at connection time. As a result, if a user is added to or removed from an IdP group, they must reconnect to Percona Server for the change to be reflected in their granted roles.

The proxying mechanism uses group membership claim instead of the token’s subject, so any token signed by a configured IdP that carries the required group is accepted. Group membership is your trust boundary in those modes, so treat it that way.

The current proxying implementation assumes the proxied user’s name matches the group name. This can be a problem when a group name isn’t a valid MySQL username (for example, it’s too long or contains disallowed characters), or when multiple groups need to map to a single account. We plan to add group-to-proxied-account mapping in future releases to address this.

The client-side plugin doesn’t verify the ID token (for example, check whether it has expired) before connecting, and the server doesn’t report the reason for access being denied (for security reasons). A good practice is to obtain a fresh token before connecting.

Conclusion

Functionally, Percona’s OpenID Connect plugin covers the same core ground as the counterpart in MySQL Enterprise Edition: signed ID tokens, claim validation, subject matching, and secure-transport enforcement.

It goes further in several important areas:

  • It is open source.
  • Keys can stay current automatically through JWKS synchronization.
  • Group-to-role mapping allows IdP group membership to drive MySQL role grants for the lifetime of the session.
  • Proxy-user support allows many IdP identities to share a smaller set of MySQL accounts.

Our OIDC implementation is suitable for real-world identity operations at scale. It can automatically map identities and groups managed by an IdP to database users and roles, and synchronize cryptographic keys.

References

  1. Percona Server for MySQL documentation: OpenID Connect authentication.
  2. Percona Server for MySQL documentation: Get started with OpenID Connect authentication.
  3. MySQL 9.7 Reference Manual: OpenID Connect Pluggable Authentication.
  4. MySQL 9.7 Reference Manual: Proxy Users.
  5. OpenID Foundation: How OpenID Connect Works
  6. auth0 Docs: JSON Web Key Sets.

Written by Michal Jankowski. Reviewed by Dennis Kittrell and Oleksiy Lukin.
Percona® is a registered trademark of Percona LLC. MySQL® is a registered trademark of Oracle Corporation.

The post OpenID Connect Authentication for MySQL, Now Fully Open Source appeared first on Percona.

Aug
31
2026
--

Rotating Expiring X.509 Certificates in Percona Server for MongoDB with Minimal Service Interruption

Expired TLS certificates can prevent new client connections and, when X.509 is used for Percona Server for MongoDB internal authentication, also prevent members of a replica set or sharded cluster from authenticating to one another.

In this post we will discuss performing a same-CA renewal: replacement certificates for server, member, and client leaf are issued by the existing trusted CA, and the X.509 attributes used for cluster membership do not change. In this scenario, the rotateCertificates command reloads TLS material for new connections without restarting mongod or mongos.

Important: Do not apply this hot-reload procedure when replacing the issuing CA, changing a certificate subject DN, or changing cluster-membership attributes. Those are not ordinary renewals.

What rotates, and what does not

Percona Server for MongoDB can reload the files configured through the following TLS options:

net:
  tls:
    mode: requireTLS
    certificateKeyFile: /etc/mongod/tls/server.pem
    CAFile: /etc/mongod/tls/ca.pem
    clusterFile: /etc/mongod/tls/cluster.pem

The certificateKeyFile contains the certificate and private key presented to normal clients. The clusterFile holds the certificate and key that a mongod or mongos process presents when connecting to other cluster members. If clusterFile is not configured, certificateKeyFile is also used for member authentication.

The rotateCertificates command affects new TLS connections. It does not terminate established client sessions or force a replica-set election.

Before the maintenance window

Begin this process well in advance of the certificate expiry, and avoid performing your first attempt in a production environment.

  1. Inventory every process and client certificates. Include all mongod members, all mongos routers, application drivers, mongosh hosts, backup jobs, monitoring, and automation tools.
  2. Confirm this is a same-CA renewal. The issuer chain trusted by every participant stays the same, and the O, OU, and DC attributes used for default internal X.509 membership matching remain unchanged.
  3. Create a new PEM file for every server and client that needs rotation. A PEM file referenced by certificateKeyFile or clusterFile must include both the certificate and its matching private key. The file must strictly contain the key first, followed by the certificate, including their encapsulation boundaries.
  4. Verify the new certificate details and validate the cert against the CA before copying to the production TLS directory

Stage a renewed server or member certificate

There are a few limitations for rotating certificates online:

  • Each new certificate must have the same filename and same filepath as the certificate it is replacing.
  • If the TLS Certificate is password-protected, its password must be the same as the old certificate it is replacing.

If CAFile, a CRL, or another configured TLS input is being renewed as part of the same operation, replace it before invoking the reload command. The command reloads the configured TLS inputs as a set; a missing or invalid input causes the reload to fail.

Luckily, incorrect certificate files will cause the rotation to fail, but will not invalidate the existing configuration or have any other side effects.

Reload one process

Connect directly to the specific mongod or mongos with an administrative user and execute the following command:

db.getSiblingDB("admin").runCommand({rotateCertificates: 1, message: "Renewed TLS certificate"})'

Immediately validate a new TLS connection to that process with a renewed client certificate. Also inspect the log for the successful certificate-rotation message and any TLS errors. Check our documentation for guidelines to perform the procedure on a replica set or sharded cluster.

Final validation and cleanup

After completing the procedure, it is a good idea to reconfirm the expiry date and SANs of the certificate presented by every mongod and mongos. Retain the old certificates only for the approved overlap period, then remove or revoke them. Don’t forget to record the new expiry dates and create alerts with enough lead time before the expiration date of the new certificates.

When the CA or member identity changes

A different procedure is required when any of the following changes:

  • The issuing CA or trusted CA chain.
  • The subject DN used by a MONGODB-X509 client user.
  • The O, OU, or DC values used for default intra-cluster X.509 membership matching.
  • net.tls.clusterAuthX509.attributes or net.tls.clusterAuthX509.extensionValue.

This is a topic for another time.

 

The post Rotating Expiring X.509 Certificates in Percona Server for MongoDB with Minimal Service Interruption appeared first on Percona.

Aug
31
2026
--

Rotating Expiring X.509 Certificates in Percona Server for MongoDB with Minimal Service Interruption

Expired TLS certificates can prevent new client connections and, when X.509 is used for Percona Server for MongoDB internal authentication, also prevent members of a replica set or sharded cluster from authenticating to one another.

In this post we will discuss performing a same-CA renewal: replacement certificates for server, member, and client leaf are issued by the existing trusted CA, and the X.509 attributes used for cluster membership do not change. In this scenario, the rotateCertificates command reloads TLS material for new connections without restarting mongod or mongos.

Important: Do not apply this hot-reload procedure when replacing the issuing CA, changing a certificate subject DN, or changing cluster-membership attributes. Those are not ordinary renewals.

What rotates, and what does not

Percona Server for MongoDB can reload the files configured through the following TLS options:

net:
  tls:
    mode: requireTLS
    certificateKeyFile: /etc/mongod/tls/server.pem
    CAFile: /etc/mongod/tls/ca.pem
    clusterFile: /etc/mongod/tls/cluster.pem

The certificateKeyFile contains the certificate and private key presented to normal clients. The clusterFile holds the certificate and key that a mongod or mongos process presents when connecting to other cluster members. If clusterFile is not configured, certificateKeyFile is also used for member authentication.

The rotateCertificates command affects new TLS connections. It does not terminate established client sessions or force a replica-set election.

Before the maintenance window

Begin this process well in advance of the certificate expiry, and avoid performing your first attempt in a production environment.

  1. Inventory every process and client certificates. Include all mongod members, all mongos routers, application drivers, mongosh hosts, backup jobs, monitoring, and automation tools.
  2. Confirm this is a same-CA renewal. The issuer chain trusted by every participant stays the same, and the O, OU, and DC attributes used for default internal X.509 membership matching remain unchanged.
  3. Create a new PEM file for every server and client that needs rotation. A PEM file referenced by certificateKeyFile or clusterFile must include both the certificate and its matching private key. The file must strictly contain the key first, followed by the certificate, including their encapsulation boundaries.
  4. Verify the new certificate details and validate the cert against the CA before copying to the production TLS directory

Stage a renewed server or member certificate

There are a few limitations for rotating certificates online:

  • Each new certificate must have the same filename and same filepath as the certificate it is replacing.
  • If the TLS Certificate is password-protected, its password must be the same as the old certificate it is replacing.

If CAFile, a CRL, or another configured TLS input is being renewed as part of the same operation, replace it before invoking the reload command. The command reloads the configured TLS inputs as a set; a missing or invalid input causes the reload to fail.

Luckily, incorrect certificate files will cause the rotation to fail, but will not invalidate the existing configuration or have any other side effects.

Reload one process

Connect directly to the specific mongod or mongos with an administrative user and execute the following command:

db.getSiblingDB("admin").runCommand({rotateCertificates: 1, message: "Renewed TLS certificate"})'

Immediately validate a new TLS connection to that process with a renewed client certificate. Also inspect the log for the successful certificate-rotation message and any TLS errors. Check our documentation for guidelines to perform the procedure on a replica set or sharded cluster.

Final validation and cleanup

After completing the procedure, it is a good idea to reconfirm the expiry date and SANs of the certificate presented by every mongod and mongos. Retain the old certificates only for the approved overlap period, then remove or revoke them. Don’t forget to record the new expiry dates and create alerts with enough lead time before the expiration date of the new certificates.

When the CA or member identity changes

A different procedure is required when any of the following changes:

  • The issuing CA or trusted CA chain.
  • The subject DN used by a MONGODB-X509 client user.
  • The O, OU, or DC values used for default intra-cluster X.509 membership matching.
  • net.tls.clusterAuthX509.attributes or net.tls.clusterAuthX509.extensionValue.

This is a topic for another time.

 

The post Rotating Expiring X.509 Certificates in Percona Server for MongoDB with Minimal Service Interruption appeared first on Percona.

Aug
25
2026
--

Software Bill of Materials in Percona Server for MongoDB

Introduction

A software bill of materials (SBOM) offers end users enhanced supply chain visibility, thereby facilitating license compliance and timely vulnerability detection. An SBOM of an application, library, or framework (collectively referred to as a “component”) is a machine-readable document that enumerates all other components it incorporates, including transitive ones. In this way, an SBOM represents the dependency graph of a particular component. For each component, including the one for which the SBOM is created, it provides the component’s specific version and license.

Given the dependency graph in the figure below, the SBOM for component A would include components B, C, and D. In addition, the SBOM would list each relationship between components (depicted as arrows in the figure) in its “dependencies” section.

Periodic SBOM scans

Given an SBOM file for a component, one can scan it for vulnerabilities with one of the many available tools. If the tool doesn’t show any, it can be tempting to declare that we are safe and forget about the SBOM until the next version of the component in question is released, together with a new SBOM. That, however, would be a mistake.

SBOM scanning tools have two data inputs. The first one is an SBOM itself. It is passed to the tool explicitly and typically doesn’t change over time for a particular component version. The second data input is the complete opposite: it is implicit and updated daily or even more often. We are talking about the vulnerability database(s). SBOM scanning tools download the updates to the vulnerability database(s) before each SBOM scan. The same scan command, using the same SBOM file that previously reported no vulnerabilities, can easily report serious vulnerabilities in an hour.

That is why it is important to run scans periodically to be notified of new vulnerabilities in a timely manner and to start remediation before the component’s maintainers prepare a fix. This is especially true in the era of AI-assisted vulnerability discovery, which often leaves maintainers overloaded with vulnerability reports, so fixing takes longer than before.

SBOMs in Percona Server for MongoDB

Since versions 7.0.39-21, 8.0.28-12, and 8.3.7-1, Percona Server for MongoDB (further referred to as PSMDB) provides SBOMs in its binary packages. In Debian and RPM packages, one can find the SBOM in the /usr/share/doc/percona-server-mongodb-server/sbom.cdx.json file once the percona-server-mongodb-server package is installed. In the binary tarball, the SBOM is located at doc/sbom.cdx.json relative to the tarball’s root directory. As you might have already guessed, the cdx extension in the filename indicates that the SBOM is in the CycloneDX format.

Percona Server for MongoDB also provides two SBOMs for its Docker images. The first one covers PSMDB exclusively and is embedded in the image’s filesystem at the same /usr/share/doc/percona-server-mongodb-server/sbom.cdx.json path. It is the same SBOM as in the corresponding RPM package. The second one covers the image as a whole, including the base OS, libraries and utilities installed on top of it, and so on. This SBOM considers PSMDB as a dependency, and is associated with the Docker image as an OCI artifact.

Since PSMDB’s second SBOM differs little from other OCI-attached SBOMs in how it is scanned, we won’t discuss it here. One can refer to the documentation for detailed instructions and examples. Instead, the rest of the post focuses on the first SBOM: the one that is included in a Debian package, an RPM package, and a binary tarball, and embedded in the Docker image.

Scanning the SBOM

One can scan PSMDB’s SBOM with grype as follows:

grype --distro ubuntu:24.04 sbom:/usr/share/doc/percona-server-mongodb-server/sbom.cdx.json

Clearly, they need to pass the distribution name and version they run PSMDB on, e.g.: —distro rhel:9.8.

One can also use OWASP Dependency Track. Instead of being a command-line utility, Dependency Track is a fully fledged GUI-based service. Nevertheless, deploying it is as easy as two shell commands:

curl -fsSLO https://dependencytrack.org/docker-compose.yml
docker compose up -d

Then, do the following:

  • Go to http://localhost:8080 and authenticate with username admin and password admin
  • Change the password and reauthenticate with the username admin and the new password
  • In the left pane, select “Projects” and then click the “Create Project” button
  • After creating the project, click on its name and select the “Component” tab
  • Click the “Upload BOM” button and upload the “sbom.cdx.json” file

At the time of writing, Grype and OWASP Dependency Track are the only tools we are aware of that can scan PSMDB’s SBOM. Other popular options, notably Trivy, skip analysis of the most PSMDB dependencies in the SBOM. This is the result of the approach to dependency management that PSMDB has to follow.

Evaluating Scanning Results

Running Grype as shown above on the SBOM from PSMDB version 7.0.39-21 gives quite a scary report (redacted for length):

$ grype --distro ubuntu:24.04 \
    sbom:/usr/share/doc/percona-server-mongodb-server/sbom.cdx.json
NAME                          INSTALLED  VULNERABILITY   SEVERITY  EPSS
unicode-org/ICU4C             57.1       CVE-2016-7415   Critical  5.8% (92nd)
unicode-org/ICU4C             57.1       CVE-2017-14952  Critical  5.1% (91st)
unicode-org/ICU4C             57.1       CVE-2016-6293   Critical  5.0% (91st)
unicode-org/ICU4C             57.1       CVE-2017-17484  Critical  4.6% (90th)
unicode-org/ICU4C             57.1       CVE-2017-7867   High      4.6% (90th)
unicode-org/ICU4C             57.1       CVE-2017-7868   High      4.4% (90th)
unicode-org/ICU4C             57.1       CVE-2020-10531  High      2.7% (84th)
unicode-org/ICU4C             57.1       CVE-2017-15422  Medium    2.5% (82nd)
unicode-org/ICU4C             57.1       CVE-2017-15396  Medium    2.2% (80th)
libtom/LibTomCrypt            1.18.2     CVE-2019-17362  Critical  3.1% (86th)
google.opensource/Protobuf    3.19.5     CVE-2024-7254   High      2.8% (84th)
c-ares/c-ares                 1.19.1     CVE-2024-25629  Medium    0.3% (27th)
pcre2/PCRE2                   10.40      CVE-2022-41409  High      1.1% (63rd)
google.opensource/gRPC (C++)  1.46.6     CVE-2026-33186  Critical  1.6% (72nd)
google.opensource/gRPC (C++)  1.46.6     CVE-2023-44487  High      100.0% (99th)
google.opensource/gRPC (C++)  1.46.6     CVE-2023-4785   High      0.7% (48th)
google.opensource/gRPC (C++)  1.46.6     CVE-2023-33953  High      0.5% (38th)
google.opensource/gRPC (C++)  1.46.6     CVE-2023-32732  Medium    0.5% (41st)
mongodb/mongodb/mongo         7.0.39     CVE-2017-2665   High      0.3% (25th)
mongodb/mongodb/mongo         7.0.39     CVE-2014-8180   Medium    0.3% (19th)
mongodb/MongoDB C Driver      1.27.6     CVE-2026-6231   High      0.2% (8th)
mongodb/MongoDB C Driver      1.27.6     CVE-2025-12119  Low       0.2% (10th)
mongodb/MongoDB C Driver      1.27.6     CVE-2026-4359   Low       0.2% (8th)

The first thing to note about the results above is that PSMDB version 7.0.39-21 does not introduce all those vulnerabilities. They have existed for a long time in the 7.0 version series; the SBOM and the scanning tools only made them visible.

We can start sorting out this pile of vulnerabilities with the critical CVE-2026-33186 in the gRPC framework. If we read its description, we will learn that it affects only the Go implementation of the framework. The C++ implementation used in PSMDB is hosted in a separate repository (https://github.com/grpc/grpc, as opposed to https://github.com/grpc/grpc-go) and is not affected by the vulnerability. But why did Grype report it then? We believe that is a result of the quite wide Common Platform Enumeration (CPE) of this component in the SBOM file:

cpe:2.3:a:grpc:grpc:1.46.6:*:*:*:*:*:*:*

In the CVEs page, CPE is cpe:2.3:a:grpc:grpc:*:*:*:*:*:go:*:* stating that only Go code is vulnerable. So the SBOM’s CPE matched the CVE’s CPE, making Grype report the vulnerability, though it is a false positive in reality.

Another gRPC vulnerability, CVE-2023-44487, does not apply to Percona Server for MongoDB either. It is exploitable only if the support of the alternative gRPC-based wire-protocol transport is enabled during the build process. It is disabled by default, though, and Percona has never enabled it.

Next, let us look at the critical CVE-2016-7415 in ICU4C, which is a C/C++ library for handling Unicode. The CVE correctly points out that version 57.1 is vulnerable to a buffer overflow. However, the PSMDB codebase has local fixes for this and other ICU4C-related CVEs. This is still version 57.1, but with fixes applied.

Finally, consider the critical vulnerability CVE-2019-17362 in LibTomCrypt. Its description says the issue is in the der_decode_utf8_string function in the der_decode_utf8_string.c file. However, Percona Server for MongoDB codebase does not even include the file: only a small part of LibTomCrypt is vendored into the PSMDB codebase, leaving der_decode_utf8_string.c aside. That brings us to the conclusion that the vulnerability does not actually affect Percona Server for MongoDB.

False Positives and Paranoia

By now, you have probably noticed a pattern here. Many of the reported CVEs are false positives, meaning that they are reported but don’t actually affect PSMDB. One may argue that Grype produces too many of them. But there are a couple of reasons for that. First, Grype could not know about local patches for some components, components excluded from the build, or partially vendored components.

Second, if we consider the “paranoia spectrum”, where the left extreme is total naivety and the right one is being suspicious even in innocent cases, it is perfectly reasonable for a security tool to lean to the right end. In our use case, that means reporting false-positive results and leaving the analysis to a human being is a much safer choice than omitting a potential issue that could turn into a serious security breach.

Vulnerability Exploitability Exchange

Repeating the analysis we showed above for each reported CVE on the user side is tedious and sometimes difficult. In theory, a user could realize CVE-2026-33186 (an issue in the Go code) and CVE-2019-17362 (an issue in the code that doesn’t actually exist in PSMDB) are false positives. But it would be unreasonable to expect a user to dig into the internals of Percona Server for MongoDB to discover that some code is excluded from the build (CVE-2023-44487) or has local patches (CVE-2016-7415).

That is why the developers of Percona Server for MongoDB conducted the analysis themselves and prepared its results as a Vulnerability Exploitability eXchange (VEX) document. Each Percona Server for MongoDB release that comes with an SBOM file (versions 7.0.39-21, 8.0.28-12, and 8.3.7-1 and above) also has a corresponding VEX document located at https://percona.github.io/percona-server-mongodb/vex/percona-server-mongodb-<version>.vex.json. Below is an example of downloading the VEX document and using it in Grype to filter out false positives for version 7.0.39-21 (redacted for length):

$ curl -fsSLO https://percona.github.io/percona-server-mongodb/vex/percona-server-mongodb-7.0.39-21.vex.json
$ grype --distro ubuntu:24.04 \
    --vex=percona-server-mongodb-7.0.39-21.vex.json \
    sbom:/usr/share/doc/percona-server-mongodb-server/sbom.cdx.json
NAME                      INSTALLED  VULNERABILITY  SEVERITY  EPSS
mongodb/MongoDB C Driver  1.27.6     CVE-2026-6231  High      0.2% (8th)

We can see that after taking a VEX document into account, only one vulnerability that actually affects PSMDB remains. What is more, a VEX document can list not only those vulnerabilities that don’t affect particular software but also those that actually do. In our case, percona-server-mongodb-7.0.39-21.vex.json says that CVE-2026-6231 would affect PSMDB only if Queryable Encryption (aka Field Level Encryption) is enabled. As a side comment, at Percona, we plan to eliminate that vulnerability in the future.

The dependency on MongoDB Community Edition

An attentive reader could have probably noticed that scanning the SBOM of Percona Server for MongoDB version 7.0.39-21 reported a couple of vulnerabilities in mongodb/mongodb/mongo, also version 7.0.39, which can look strange, but it is actually not. Percona Server for MongoDB is a fork and a drop-in replacement of MongoDB Community Edition. That is the reason every vulnerability that affects the latter also affects the former. Percona Server for MongoDB having a “dependency” on MongoDB Community Edition enables SBOM scanning tools to detect vulnerabilities in the MongoDB Community Edition code itself, in addition to those in its dependencies.

Shared Libraries

Even if an SBOM scanning tool had shown no CVEs after being passed a VEX file, we still can’t conclude that our PSMDB deployment is free from known vulnerabilities. That is because an SBOM file can’t cover dependencies linked to Percona Server for MongoDB at runtime as shared libraries. Their specific versions are governed by a particular OS and can change over time. Even if the PSMDB package for a particular OS version included shared libraries specifying their versions at build time, any upgrade of the packages on the machine where PSMDB is installed could make those versions incorrect.

In addition to periodically scanning the Percona Server for MongoDB SBOM, we recommend that users download and scan the SBOMs for the shared libraries that Percona Server for MongoDB directly links to at runtime. At the time of writing, those libraries are:

Name Typical Linked Library Filename(s)
GNU C Library libc.so.6, libm.so.6, libresolv.so.2, etc.
GCC Support Library libgcc_s.so.1
libcurl libcurl.so.4
Cyrus SASL libsasl2.so.2
Kerberos 5 GSS-API libgssapi_krb5.so.2
OpenLDAP liblber.so.2, libldap.so.2
OpenSSL libcrypto.so.3, libssl.so.3

Please note version numbers in library filenames above (e.g. 6 in libc.so.6). They are just examples and can differ from platform to platform.

Conclusion

Percona Server for MongoDB has provided SBOM and VEX documents since versions 7.0.39-21, 8.0.28-12, and 8.3.7-1, giving users better visibility into its supply chain for both licensing and security. Regularly scanning PSMDB’s SBOM, along with the SBOMs of the shared libraries it links to, helps operators detect potential vulnerabilities and begin remediation before they become security breaches.

The post Software Bill of Materials in Percona Server for MongoDB appeared first on Percona.

Jul
24
2026
--

Alert on CVEs in Your Percona Tools for MongoDB on Day One

TL;DR: Starting with PBM 2.15.0 and PCSM 0.9.0, every release artifact – binary tarballs, RPM and DEB packages, and Docker images – ships a CycloneDX 1.6 Software Bill of Materials in JSON. Scan it with Trivy, Grype, or any CycloneDX-compatible tool. For Docker images, the fastest path is a Trivy image –sbom-sources oci <image>. There is nothing to enable, as the SBOM is already a part of the artifact you were going to download.

If you run Percona Backup for MongoDB (PBM) or Percona ClusterSync for MongoDB (PCSM), both part of the Percona Software for MongoDB family, you can now answer one of the stressful questions in operations: “Is my database tooling affected by this CVE?” in seconds instead of days. And when a customer or auditor asks for a parts list of what you deployed, you can hand it over as a single file instead of starting a multi-day investigation.

That parts list is a Software Bill of Materials (SBOM), and starting with PBM 2.15.0 and PCSM 0.9.0, it comes along in every channel we publish – tarballs, RPM and DEB packages, and Docker images. This post shows what is in it, where to find it, and three ways to scan it.

The problem: you can’t patch what you can’t see

Most MongoDB operators run database tooling assembled by someone else – official RPMs, official containers, official tarballs. When something goes wrong upstream, the first question is always the same: what is actually inside this artifact, and is any of it affected?

Two incidents made that question a board-level concern, and a third made it personal for MongoDB teams. Log4Shell in late 2021 forced thousands of teams to manually audit Java dependencies they did not know they had. The xz-utils backdoor disclosed in early 2024 hid in a compression library buried deep inside Linux base images. Then, in December 2025, MongoBleed (CVE-2025-14847) forced MongoDB teams to urgently identify which server and tooling versions were actually deployed. In every case, teams that already had an SBOM per artifact answered “are we affected?” in minutes; teams that did not took days.

The other version of the problem is that the SBOM is something someone else asks of you – a customer running a security review, an auditor checking EU Cyber Resilience Act or US Executive Order 14028 compliance, or a procurement team working through a vendor questionnaire. Without one, every such request turns into a discovery project.

What Percona Backup for MongoDB and ClusterSync now ship

An SBOM is a machine-readable inventory of every component, library, and OS package inside a built artifact, with versions, licenses, and dependency relationships. Think of it as a packing slip for a software shipment, except a computer can parse it, search it, and cross-reference it against vulnerability databases.

Plenty of vendors now ship SBOMs. What matters is whether the SBOM is actually usable, and PBM and PCSM cover the three things that decide that. The format is CycloneDX 1.6, an OWASP-backed JSON standard that every major tool reads: Trivy, Grype, Snyk, and Dependency-Track. The files are generated with Syft from the actual built binary and the staged file tree, so the inventory reflects what was really packaged, not what the source tree implies. And the SBOM ships in every distribution channel, not just one:

Distribution channel SBOM location
Binary tarball <product>-<version>.cdx.json at the root of the archive
RPM package /usr/share/doc/<product>/<product>-<version>.cdx.json
DEB package /usr/share/doc/<product>/<product>-<version>.cdx.json
Docker image Two SBOMs ship side by side — see below

Docker images carry two SBOMs

Docker images get special treatment because they bundle two different things: our binary on top of a base operating system. Each PBM and PCSM image, therefore, carries two SBOMs with overlapping scopes.

The embedded SBOM is stored in the image filesystem (the same file the RPM installs) and describes our binary and its Go modules. This is the SBOM to use in offline or air-gapped clusters where you cannot reach a registry.

The OCI-attached SBOM lives next to the image in the registry as an OCI 1.1 referrer artifact and describes the full image, including the base OS packages. This is the canonical SBOM for a Docker image, and the easiest to fetch programmatically.

SBOM Scope / how you reach it
Embedded (installed by the RPM) Our package only: Go modules of the binary; inside the image filesystem
OCI-attached (registry-side) Full image: our package + UBI9 OS packages; via the OCI Referrers API

 

How the SBOM is generated across PBM and PCSM artifacts, and why a Docker image carries two.

Three ways to scan your SBOM

The examples below use Trivy because it is the most common choice in Percona QA pipelines, but Grype, Snyk, and any other CycloneDX-compatible scanner accept the same .cdx.json files unchanged. By default, these commands report everything the scanner finds. In a CI pipeline, you would want to narrow down the output by leaving only –severity HIGH, CRITICAL to focus on the most serious findings, and –ignore-unfixed to skip CVEs that have no upstream fix yet.

  • From a downloaded package or tarball

Once the artifact is on disk, the SBOM is just a file in a predictable location. Point Trivy at it:

trivy sbom --severity HIGH,CRITICAL,MEDIUM,LOW \
    /usr/share/doc/percona-clustersync-mongodb/percona-clustersync-mongodb-0.9.0.cdx.json

The same command works against the SBOM extracted from a tarball or installed by an RPM or DEB package – only the file path changes. For Oracle Linux, replace with the exact compatible RHEL minor, e.g., --distro redhat/9.8, since Trivy does not recognize the ol OS family on its own, but the RHEL vulnerability database is binary-compatible.

  • From a Docker image, without pulling it

For Docker images, Trivy can fetch the OCI-attached SBOM straight from the registry. No image pull, no extraction step:

trivy image --severity HIGH,CRITICAL,MEDIUM,LOW --sbom-sources oci \
    docker.io/percona/percona-clustersync-mongodb:0.9.0

Trivy resolves the multi-arch index, picks your platform-specific child digest, asks the registry for any attached SBOMs via the OCI Referrers API, and scans whichever one it finds. A typical run looks like this:

Report Summary:

Target Type Vulnerabilities
docker.io/percona/percona-clustersync-mongodb:0.9.0 (redhat 9.8) redhat 0
usr/bin/pcsm gobinary 8

Two targets, two scopes: the base OS layer (no findings) and the PCSM binary (eight Go standard-library CVEs, all flagged because the image was built against a Go release that has since been superseded). The same –sbom-sources oci flag works for PBM images, and against both the public percona/ images on Docker Hub and the engineering perconalab/ images.

  • By hand, with ORAS

If you would rather inspect the OCI artifact directly, to confirm what is attached, or pull the SBOM to disk, the ORAS CLI does that without a scanner in the loop:

oras discover --format tree \
    docker.io/percona/percona-clustersync-mongodb:0.9.0-amd64

The per-arch tag (:<version>-<arch>) resolves straight to the image manifest that the SBOM is attached to. From there, oras pull <digest> writes the .cdx.json to disk for archival or for feeding into a scanner of your choice.

What changes for you

For operators, the upgrade story gets simpler. When a new CVE is disclosed, you no longer have to guess whether your PBM or PCSM deployment is affected; you scan the SBOM that shipped with the exact version you are running and get a yes/no answer in seconds. The SBOM is also a stable input for the dashboards you already run (Dependency-Track, DefectDojo, your SIEM), so PBM and PCSM are no longer blind spots in the inventory.

For security and platform teams, the OCI-attached SBOM means you can pre-screen container images in CI before they ever reach a cluster. Pull-request gates that already scan first-party images for HIGH/CRITICAL findings can pick up PBM and PCSM with no extra glue code: –sbom-sources oci is enough.

 

Try it on your own deployment

SBOMs ship starting with PBM 2.15.0 and PCSM 0.9.0 across every channel we publish: tarballs, RPM, DEB, and Docker. There is nothing to switch on: download the artifact you would have downloaded, and the SBOM is already there.Full details, including the ORAS walkthrough and per-channel paths, are in the PBM and PCSM documentation (PBM, PCSM).&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;/p>

Run a scanner over your Percona Backup for MongoDB or Percona ClusterSync for MongoDB deployment using one of the commands above. If the result surprises you in any direction, if you have a finding you would like us to address, or if a workflow did not behave as our docs imply, we would like to hear about it, and the SBOM lets you point us to the exact component and version rather than a hunch. Open an issue in the PBM or PCSM Jira project, or stop by the Percona Community Forum.

One last thing: an SBOM tells you what is inside the artifact, not what we have determined about each finding. That second part is coming. Alongside the per-artifact SBOMs described here, we also plan to publish source SBOMs in the repository, and a follow-up in this series will cover the VEX (Vulnerability Exploitability eXchange) documents that record, for each finding, whether it is fixed, not exploitable in our build, or still under investigation. Watch for both in future re

leases.

The post Alert on CVEs in Your Percona Tools for MongoDB on Day One appeared first on Percona.

Jul
24
2026
--

Alert on CVEs in Your Percona Tools for MongoDB on Day One

TL;DR: Starting with PBM 2.15.0 and PCSM 0.9.0, every release artifact – binary tarballs, RPM and DEB packages, and Docker images – ships a CycloneDX 1.6 Software Bill of Materials in JSON. Scan it with Trivy, Grype, or any CycloneDX-compatible tool. For Docker images, the fastest path is a Trivy image –sbom-sources oci <image>. There is nothing to enable, as the SBOM is already a part of the artifact you were going to download.

If you run Percona Backup for MongoDB (PBM) or Percona ClusterSync for MongoDB (PCSM), both part of the Percona Software for MongoDB family, you can now answer one of the stressful questions in operations: “Is my database tooling affected by this CVE?” in seconds instead of days. And when a customer or auditor asks for a parts list of what you deployed, you can hand it over as a single file instead of starting a multi-day investigation.

That parts list is a Software Bill of Materials (SBOM), and starting with PBM 2.15.0 and PCSM 0.9.0, it comes along in every channel we publish – tarballs, RPM and DEB packages, and Docker images. This post shows what is in it, where to find it, and three ways to scan it.

The problem: you can’t patch what you can’t see

Most MongoDB operators run database tooling assembled by someone else – official RPMs, official containers, official tarballs. When something goes wrong upstream, the first question is always the same: what is actually inside this artifact, and is any of it affected?

Two incidents made that question a board-level concern, and a third made it personal for MongoDB teams. Log4Shell in late 2021 forced thousands of teams to manually audit Java dependencies they did not know they had. The xz-utils backdoor disclosed in early 2024 hid in a compression library buried deep inside Linux base images. Then, in December 2025, MongoBleed (CVE-2025-14847) forced MongoDB teams to urgently identify which server and tooling versions were actually deployed. In every case, teams that already had an SBOM per artifact answered “are we affected?” in minutes; teams that did not took days.

The other version of the problem is that the SBOM is something someone else asks of you – a customer running a security review, an auditor checking EU Cyber Resilience Act or US Executive Order 14028 compliance, or a procurement team working through a vendor questionnaire. Without one, every such request turns into a discovery project.

What Percona Backup for MongoDB and ClusterSync now ship

An SBOM is a machine-readable inventory of every component, library, and OS package inside a built artifact, with versions, licenses, and dependency relationships. Think of it as a packing slip for a software shipment, except a computer can parse it, search it, and cross-reference it against vulnerability databases.

Plenty of vendors now ship SBOMs. What matters is whether the SBOM is actually usable, and PBM and PCSM cover the three things that decide that. The format is CycloneDX 1.6, an OWASP-backed JSON standard that every major tool reads: Trivy, Grype, Snyk, and Dependency-Track. The files are generated with Syft from the actual built binary and the staged file tree, so the inventory reflects what was really packaged, not what the source tree implies. And the SBOM ships in every distribution channel, not just one:

Distribution channel SBOM location
Binary tarball <product>-<version>.cdx.json at the root of the archive
RPM package /usr/share/doc/<product>/<product>-<version>.cdx.json
DEB package /usr/share/doc/<product>/<product>-<version>.cdx.json
Docker image Two SBOMs ship side by side — see below

Docker images carry two SBOMs

Docker images get special treatment because they bundle two different things: our binary on top of a base operating system. Each PBM and PCSM image, therefore, carries two SBOMs with overlapping scopes.

The embedded SBOM is stored in the image filesystem (the same file the RPM installs) and describes our binary and its Go modules. This is the SBOM to use in offline or air-gapped clusters where you cannot reach a registry.

The OCI-attached SBOM lives next to the image in the registry as an OCI 1.1 referrer artifact and describes the full image, including the base OS packages. This is the canonical SBOM for a Docker image, and the easiest to fetch programmatically.

SBOM Scope / how you reach it
Embedded (installed by the RPM) Our package only: Go modules of the binary; inside the image filesystem
OCI-attached (registry-side) Full image: our package + UBI9 OS packages; via the OCI Referrers API

 

How the SBOM is generated across PBM and PCSM artifacts, and why a Docker image carries two.

Three ways to scan your SBOM

The examples below use Trivy because it is the most common choice in Percona QA pipelines, but Grype, Snyk, and any other CycloneDX-compatible scanner accept the same .cdx.json files unchanged. By default, these commands report everything the scanner finds. In a CI pipeline, you would want to narrow down the output by leaving only –severity HIGH, CRITICAL to focus on the most serious findings, and –ignore-unfixed to skip CVEs that have no upstream fix yet.

  • From a downloaded package or tarball

Once the artifact is on disk, the SBOM is just a file in a predictable location. Point Trivy at it:

trivy sbom --severity HIGH,CRITICAL,MEDIUM,LOW \
    /usr/share/doc/percona-clustersync-mongodb/percona-clustersync-mongodb-0.9.0.cdx.json

The same command works against the SBOM extracted from a tarball or installed by an RPM or DEB package – only the file path changes. For Oracle Linux, replace with the exact compatible RHEL minor, e.g., --distro redhat/9.8, since Trivy does not recognize the ol OS family on its own, but the RHEL vulnerability database is binary-compatible.

  • From a Docker image, without pulling it

For Docker images, Trivy can fetch the OCI-attached SBOM straight from the registry. No image pull, no extraction step:

trivy image --severity HIGH,CRITICAL,MEDIUM,LOW --sbom-sources oci \
    docker.io/percona/percona-clustersync-mongodb:0.9.0

Trivy resolves the multi-arch index, picks your platform-specific child digest, asks the registry for any attached SBOMs via the OCI Referrers API, and scans whichever one it finds. A typical run looks like this:

Report Summary:

Target Type Vulnerabilities
docker.io/percona/percona-clustersync-mongodb:0.9.0 (redhat 9.8) redhat 0
usr/bin/pcsm gobinary 8

Two targets, two scopes: the base OS layer (no findings) and the PCSM binary (eight Go standard-library CVEs, all flagged because the image was built against a Go release that has since been superseded). The same –sbom-sources oci flag works for PBM images, and against both the public percona/ images on Docker Hub and the engineering perconalab/ images.

  • By hand, with ORAS

If you would rather inspect the OCI artifact directly, to confirm what is attached, or pull the SBOM to disk, the ORAS CLI does that without a scanner in the loop:

oras discover --format tree \
    docker.io/percona/percona-clustersync-mongodb:0.9.0-amd64

The per-arch tag (:<version>-<arch>) resolves straight to the image manifest that the SBOM is attached to. From there, oras pull <digest> writes the .cdx.json to disk for archival or for feeding into a scanner of your choice.

What changes for you

For operators, the upgrade story gets simpler. When a new CVE is disclosed, you no longer have to guess whether your PBM or PCSM deployment is affected; you scan the SBOM that shipped with the exact version you are running and get a yes/no answer in seconds. The SBOM is also a stable input for the dashboards you already run (Dependency-Track, DefectDojo, your SIEM), so PBM and PCSM are no longer blind spots in the inventory.

For security and platform teams, the OCI-attached SBOM means you can pre-screen container images in CI before they ever reach a cluster. Pull-request gates that already scan first-party images for HIGH/CRITICAL findings can pick up PBM and PCSM with no extra glue code: –sbom-sources oci is enough.

 

Try it on your own deployment

SBOMs ship starting with PBM 2.15.0 and PCSM 0.9.0 across every channel we publish: tarballs, RPM, DEB, and Docker. There is nothing to switch on: download the artifact you would have downloaded, and the SBOM is already there.Full details, including the ORAS walkthrough and per-channel paths, are in the PBM and PCSM documentation (PBM, PCSM).&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;/p>

Run a scanner over your Percona Backup for MongoDB or Percona ClusterSync for MongoDB deployment using one of the commands above. If the result surprises you in any direction, if you have a finding you would like us to address, or if a workflow did not behave as our docs imply, we would like to hear about it, and the SBOM lets you point us to the exact component and version rather than a hunch. Open an issue in the PBM or PCSM Jira project, or stop by the Percona Community Forum.

One last thing: an SBOM tells you what is inside the artifact, not what we have determined about each finding. That second part is coming. Alongside the per-artifact SBOMs described here, we also plan to publish source SBOMs in the repository, and a follow-up in this series will cover the VEX (Vulnerability Exploitability eXchange) documents that record, for each finding, whether it is fixed, not exploitable in our build, or still under investigation. Watch for both in future re

leases.

The post Alert on CVEs in Your Percona Tools for MongoDB on Day One appeared first on Percona.

Jul
02
2026
--

Still on MySQL 5.7 or 8.0? Those high-severity CVE fixes are covered

Upstream MySQL published an out-of-schedule release this week with two high-severity CVE fixes. If you’re running Percona Server for MySQL 5.7 or 8.0 under Extended Lifecycle Support (ELS), the program we previously called Post EOL Support, you don’t have to do anything to qualify for them. We’ve already applied the fixes and re-released the affected ELS builds.

This is the point of ELS. When a major version reaches End of Life (EOL), the community stops shipping patches, but the databases running on it don’t stop mattering. ELS keeps critical bug and security fixes coming for versions that are past their EOL date, so you can stay on 5.7 or 8.0 on your own timeline instead of a deadline someone else set.

What we did

These CVE fixes landed upstream outside the normal cadence. Under ELS, customers are entitled to security fixes for the versions they run, so we pulled the patches into the 5.7 and 8.0 builds and re-released them. ELS customers will get access to the updated builds from the usual private repository in the next couple of weeks.

Why this matters if you’re still on 5.7 or 8.0

Percona Server for MySQL 5.7 reached EOL in October 2023. Percona Server for MySQL 8.0 reached EOL in April 2026. Plenty of production systems are still on both, and not every migration can happen on the upstream’s schedule. Running an unpatched database past EOL is where the real risk sits: no security fixes, no bug fixes, and no support when something breaks at 2:00 a.m.

ELS closes that gap. You keep getting the critical fixes, including out-of-schedule security patches like these, while you plan an upgrade on terms that work for your team.

Where to go from here

If you’re on 5.7 or 8.0 and don’t have ELS in place, now is a good time to look at it. The fixes we just shipped are exactly what the program is for. See the details for your version: Extended Lifecycle Support for MySQL 8.0 or Extended Lifecycle Support for MySQL 5.7. Or reach out via percona.com or the Percona Community Forum to discuss coverage for your environment.

 


Written by @Dennis Kittrell – Reviewed by @Matthew Boehm & @Varun Nagaraju

The post Still on MySQL 5.7 or 8.0? Those high-severity CVE fixes are covered appeared first on Percona.

Jun
29
2026
--

Skipping Percona Server for MySQL 8.4.9 and 9.7.0

Upstream MySQL published an out-of-schedule release this week with two high-severity CVE fixes. We’ve pulled those fixes into our next builds and are skipping the two versions we had already queued: Percona Server for MySQL 8.4.9 and 9.7.0.

These fixes arrived through Oracle’s new monthly Critical Security Patch Updates (CSPUs), which Oracle announced begin May 28, 2026. CSPUs ship targeted high-severity fixes between Oracle’s quarterly Critical Patch Updates. For MySQL, these updates are issued as needed rather than on a fixed monthly schedule, so out-of-schedule security fixes like these may become more common.

We’ve handled a skip like this before. When MySQL Community Server 8.4.2 followed 8.4.1 by only a few weeks, we skipped 8.4.1 and shipped its contents in 8.4.2-2. This is the same approach.

What’s happening

The code for 8.4.9 and 9.7.0 was already ready for packaging when the CVE fixes landed. Rather than ship those builds and follow immediately with a security patch, we applied the fixes, re-tested, and re-tagged. Percona Server for MySQL 8.4.10 and 9.7.1 will carry everything 8.4.9 and 9.7.0 would have contained, plus the upstream high-severity CVE fixes.

These fixes come from Oracle’s June 2026 Critical Security Patch Update; the specific CVE identifiers will be listed in the 8.4.10 and 9.7.1 release notes. No action is required on your part. The fixes reach you in 8.4.10 and 9.7.1, expected within days. If your security policy requires faster remediation, contact Percona Support to discuss interim options.

8.4.9 and 9.7.0 will not appear in the package repositories. A normal upgrade moves you straight to 8.4.10 or 9.7.1, which carry the skipped versions’ content.

Who this affects

If you were waiting specifically for 8.4.9 or 9.7.0, those versions won’t be published. Point your upgrade at the next releases instead, which include the same content and the CVE fixes. The delay is a few days, not weeks. If you weren’t tracking a specific version number, nothing changes for you.

What to do

Nothing urgent. Upgrade to the next Percona Server for MySQL releases as you normally would once they’re published. We’ll announce them through release notes and the Percona Blog. For questions about timing or the security content, reach out to Percona Support or post in the Percona Community Forum.

What to expect going forward

Oracle’s monthly CSPUs mean out-of-schedule fixes will happen more often. Our approach stays consistent: we evaluate every upstream release, and when high-severity fixes land between our scheduled releases, we fold them into the next release rather than shipping a separate build for each one. Your LTS support commitments don’t change. We’re watching how often Oracle uses the monthly cadence and will adjust release planning if the volume warrants it.

The post Skipping Percona Server for MySQL 8.4.9 and 9.7.0 appeared first on Percona.

Apr
13
2026
--

Auditing Login Attempts in MySQL and MariaDB

My colleague Miguel wrote about ways to audit login attempts in MySQL over 13 years ago, and this is still a relevant subject. I decided to refresh this topic to include some important changes since then.

Very often, it is important to track login attempts to our databases due to security reasons as well as to catch application misconfigurations. I’ll focus here on the most convenient ways to log authentication attempts. While auditing all client connections is usually pointless on busy production systems, when even thousands of new client sessions may be authenticating per second, let’s concentrate especially on the failed ones.

The Error Log

All MySQL and MariaDB variants have an easy way of logging failed authentication attempts in the standard error log via elevated log verbosity. To enable it, in older MySQL versions up to 5.7, as well as in all MariaDB versions, set log_warnings = 2 (or higher).

In MySQL 5.7+, the role of setting the error log talkativeness was moved to the new variable: log_error_verbosity. MySQL 8.0+ no longer recognizes log_warnings. To log failed logins, set log_error_verbosity = 3 instead.

An example log entry when login credentials were incorrect may look like this:

2026-02-24T20:36:09.186218Z 22 [Note] [MY-010926] [Server] Access denied for user 'myuser2'@'192.168.121.12' (using password: YES)

Another error occurs when user credentials are fine, but the user does not have privileges to access a given database:

2026-02-24T23:12:19.600451Z 35 [Note] [MY-010914] [Server] Access denied for user 'myuser'@'192.168.46.%' to database 'test1'

Now, the problem with this is that the above note will only be printed when there is a system user allowing the source hostname, IP address, or subnet, and the actual username authentication phase is engaged. When the host is rejected early, we will not find anything in the error log! Only the client side will receive a rejection message, like this one:

$ mysql -h192.168.46.20 -uuser
ERROR 1130 (HY000): Host '192.168.46.13' is not allowed to connect to this MySQL server

Therefore, the error log cannot provide the complete information about failed login attempts if some are incoming from undefined hosts. Btw, the general log does not log these either.

The Audit Log (old type)

The traditional Audit Log Plugin feature, available in all recent MySQL variants, allows us to limit logging for connection activities, while we can ignore other queries. Unfortunately, we cannot log only failed logins, so the log may grow very fast when applications actively open new connections, and further filtering for failed attempts has to be done externally.

In Percona Audit Log Plugin, it can be done via the policy setting: audit_log_policy = LOGINS.

An example of a netcat TCP probe will result in the following audit log entry:

tail -1 /var/lib/mysql/audit.log |jq
{
  "audit_record": {
    "name": "Connect",
    "record": "2138_2026-02-26T09:32:27",
    "timestamp": "2026-02-26T09:33:54Z",
    "connection_id": "13",
    "status": 1158,
    "user": "",
    "priv_user": "",
    "os_login": "",
    "proxy_user": "",
    "host": "test-host1",
    "ip": "192.168.46.12",
    "db": ""
  }
}

The entry provides a status error code:

$ perror 1158
MySQL error code MY-001158 (ER_NET_READ_ERROR): Got an error reading communication packets

Interestingly, the corresponding error log entry has the same message with a different code:

2026-02-26T09:33:54.917323Z 13 [Note] [MY-010914] [Server] Got an error reading communication packets

Another example of an unknown user login attempt:

{
  "audit_record": {
    "name": "Connect",
    "record": "2142_2026-02-26T09:32:27",
    "timestamp": "2026-02-26T09:39:45Z",
    "connection_id": "17",
    "status": 1045,
    "user": "wronguser",
    "priv_user": "",
    "os_login": "",
    "proxy_user": "",
    "host": "test-host1",
    "ip": "192.168.46.12",
    "db": ""
  }
}

Here, we can determine that the user part is wrong, as the priv_user field is empty.

A typical legit client session will have two entries, with status “0”, i.e:

{"audit_record":{"name":"Connect","record":"2145_2026-02-26T09:32:27","timestamp":"2026-02-26T09:42:27Z","connection_id":"19","status":0,"user":"myuser","priv_user":"myuser","os_login":"","proxy_user":"","host":"test-host1","ip":"192.168.46.13","db":""}}
{"audit_record":{"name":"Quit","record":"2146_2026-02-26T09:32:27","timestamp":"2026-02-26T09:42:27Z","connection_id":"19","status":0,"user":"myuser","priv_user":"myuser","os_login":"","proxy_user":"","host":"test-host1","ip":"192.168.46.13","db":""}}

In the MariaDB Audit Plugin, connection events can be logged via the server_audit_events = CONNECT setting. An example logging attempt with the wrong password would be seen as:

20260226 10:52:48,test-host1,root,localhost,8,0,FAILED_CONNECT,,,1045
20260226 10:52:48,test-host1,root,localhost,8,0,DISCONNECT,,,0

The Audit Log Filter (new type)

The new audit log functionality comes as a plugin in versions 8.0.x or a component in versions 8.4+, and provides way higher flexibility and finer-grained control on what and when is logged.

With Audit Log Filter, to minimize noise and overhead, it is possible to log only failed login attempts, so legitimate application sessions won’t flood the log.

Here is an example of how to enable such a filter rule:

mysql› SELECT audit_log_filter_set_filter(
  'failed_logins_only',
  '{
    "filter": {
      "log": false,
      "class": {
        "name": "connection",
        "event": {
          "name": "connect",
          "log": {
            "not": {
              "field": { "name": "status", "value": "0" }
            }
          }
        }
      }
    }
  }'
);
mysql› SELECT audit_log_filter_set_user('%', 'failed_logins_only');

The above rules set logging for the connection class, for all events that resulted in an error (status is not success).

An example entry for a client trying to authenticate with the wrong user credentials may look like this (if JSON format is used):

{
    "timestamp": "2026-03-05 11:31:12",
    "id": 8,
    "class": "connection",
    "event": "connect",
    "connection_id": 31,
    "account": { "user": "wronguser", "host": "" },
    "login": { "user": "wronguser", "os": "", "ip": "192.168.121.16", "proxy": "" },
    "connection_data": {
      "connection_type": "ssl",
      "status": 1045,
      "db": ""
    },
    "connection_attributes": {
      "_pid": "3608615",
      "_platform": "x86_64",
      "_os": "Linux",
      "_client_name": "libmysql",
      "os_user": "przemek",
      "_client_version": "8.4.7-7"
    }
  }

And a simple TCP probe (netcat) may look like this:

{
    "timestamp": "2026-03-05 11:31:26",
    "id": 9,
    "class": "connection",
    "event": "connect",
    "connection_id": 32,
    "account": { "user": "", "host": "test-host1" },
    "login": { "user": "", "os": "", "ip": "192.168.46.13", "proxy": "" },
    "connection_data": {
      "connection_type": "tcp/ip",
      "status": 1158,
      "db": ""
    }
  }

Unfortunately, again, connections from unknown hosts are not logged. Logging attempts aborted early on the host validation phase, do not reach the audit log or any other log! This is because the validation occurs at the very beginning of the handshake workflow, and if it returns failure, the connection is terminated before reaching the logging capabilities.

To workaround this limitation and make all unsuccessful login attempts be logged, we need to create a catch-all user account. However, we don’t want to extend the possible attack surface at the same time, so let’s disable authentication entirely for such an account. We will need the no-login plugin first:

INSTALL PLUGIN mysql_no_login SONAME 'mysql_no_login.so';

Now, the following user entry will allow auditing connection attempts from any host/IP:

CREATE USER ''@'%' IDENTIFIED WITH mysql_no_login;

Now, specific port knocking may still not be logged, like with nmap, as the client sends a RST packet even before the initial MySQL “hello” packet. So, we will not see this session anywhere in the MySQL logs:

$ nmap 192.168.46.20 -sT -p 3306
Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-03-11 07:24 CET
Nmap scan report for 192.168.46.20 (192.168.46.20)
Host is up (0.00021s latency).
PORT     STATE SERVICE
3306/tcp open  mysql
Nmap done: 1 IP address (1 host up) scanned in 0.02 seconds

The only way to capture the above would be to watch the wire protocol, i.e., with tcpdump.

Additional Instrumentation

The error log entries can be viewed in a more structured manner, with the P_S table, so the entry:

2026-02-25T20:46:40.779435Z 66 [Note] [MY-010926] [Server] Access denied for user 'wronguser'@'test-host1' (using password: YES)

Will have equivalent in:

mysql› select * from performance_schema.error_log order by LOGGED desc limit 1?G
*************************** 1. row ***************************
    LOGGED: 2026-02-25 20:46:40.779435
 THREAD_ID: 66
      PRIO: Note
ERROR_CODE: MY-010926
 SUBSYSTEM: Server
      DATA: Access denied for user 'wronguser'@'test-host1' (using password: YES)
1 row in set (0.00 sec)

And it allows SQL queries against the log, like aggregations:

mysql› select count(*) from performance_schema.error_log where ERROR_CODE='MY-010926';
+----------+
| count(*) |
+----------+
|       11 |
+----------+
1 row in set (0.00 sec)

Also, MySQL keeps track of connection attempts from external hosts in the host cache structure, which can be observed via performance_schema.host_cache view. The view provides statistics on the number of failed connections grouped by reason categories, together with success and failure timestamps. This view provides information only about source hosts’ connection events, but not users. An example output may look like this:

mysql› select * from performance_schema.host_cache?G
*************************** 1. row ***************************
                                        IP: 192.168.46.12
                                      HOST: test-host1
                            HOST_VALIDATED: YES
                        SUM_CONNECT_ERRORS: 2
                 COUNT_HOST_BLOCKED_ERRORS: 0
           COUNT_NAMEINFO_TRANSIENT_ERRORS: 0
           COUNT_NAMEINFO_PERMANENT_ERRORS: 0
                       COUNT_FORMAT_ERRORS: 0
           COUNT_ADDRINFO_TRANSIENT_ERRORS: 0
           COUNT_ADDRINFO_PERMANENT_ERRORS: 0
                       COUNT_FCRDNS_ERRORS: 0
                     COUNT_HOST_ACL_ERRORS: 0
               COUNT_NO_AUTH_PLUGIN_ERRORS: 0
                  COUNT_AUTH_PLUGIN_ERRORS: 3
                    COUNT_HANDSHAKE_ERRORS: 2
                   COUNT_PROXY_USER_ERRORS: 0
               COUNT_PROXY_USER_ACL_ERRORS: 0
               COUNT_AUTHENTICATION_ERRORS: 5
                          COUNT_SSL_ERRORS: 0
         COUNT_MAX_USER_CONNECTIONS_ERRORS: 0
COUNT_MAX_USER_CONNECTIONS_PER_HOUR_ERRORS: 0
             COUNT_DEFAULT_DATABASE_ERRORS: 2
                 COUNT_INIT_CONNECT_ERRORS: 0
                        COUNT_LOCAL_ERRORS: 0
                      COUNT_UNKNOWN_ERRORS: 0
                                FIRST_SEEN: 2026-02-25 20:41:57
                                 LAST_SEEN: 2026-02-26 09:02:35
                          FIRST_ERROR_SEEN: 2026-02-25 20:42:17
                           LAST_ERROR_SEEN: 2026-02-26 09:02:38
1 row in set (0.00 sec)

Depending on what was wrong with the connection or authentication attempt, a different counter will increment. For instance, when a user tries to log in with the default database, it does not have the privilege to, the COUNT_DEFAULT_DATABASE_ERRORS will increase. When an unknown user tries to log in without a password, the COUNT_AUTH_PLUGIN_ERRORS is used, but when any user (existing or not) tries a wrong password, the COUNT_AUTHENTICATION_ERRORS gets used instead.

Some cases of port probing, for example, using telnet or netcat, will increment COUNT_HANDSHAKE_ERRORS. Interestingly, though, the nmap probe does not increment any of them.

Also, when there is no catch-all user and no user entry matching the source IP/host/network, the host_cache table will allow us to at least observe statistics about failed logins per source IP, as each connection refused on the host validation phase will increment the COUNT_HOST_ACL_ERRORS counter.

Some limited visibility into failed login attempts can be available via the Connection Control Plugin. However, this plugin’s main purpose is not auditing, but rather slowing down brute force attacks against MySQL user accounts. Still, when installed, failed attempt counts are visible via the following view:

mysql› select * from information_schema.CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS;
+---------------------+-----------------+
| USERHOST            | FAILED_ATTEMPTS |
+---------------------+-----------------+
| ''@'test-host1'     |              10 |
| ''@'192.168.121.13' |               4 |
| 'root'@'localhost'  |               3 |
| ''@'%'              |              10 |
+---------------------+-----------------+
4 rows in set (0.01 sec)

Finally, another per-user view was added in recent Percona Server versions, which shows how many failed login attempts are left until the account gets locked. This feature is active (tracking active) only for the accounts that have the FAILED_LOGIN_ATTEMPTS and PASSWORD_LOCK_TIME limitations:

mysql› select * from performance_schema.account_failed_login_lock_status;
+-------------------+-----------+--------------------+--------------+--------------------+-----------+--------------------+-----------------------+
| USER              | HOST      | IS_TRACKING_ACTIVE | MAX_ATTEMPTS | PASSWORD_LOCK_DAYS | IS_LOCKED | REMAINING_ATTEMPTS | REMAINING_DAYS_LOCKED |
+-------------------+-----------+--------------------+--------------+--------------------+-----------+--------------------+-----------------------+
| mysql.infoschema  | localhost | NO                 |            0 |                  0 | NULL      |               NULL |                  NULL |
| mysql.session     | localhost | NO                 |            0 |                  0 | NULL      |               NULL |                  NULL |
| mysql.sys         | localhost | NO                 |            0 |                  0 | NULL      |               NULL |                  NULL |
| percona.telemetry | localhost | NO                 |            0 |                  0 | NULL      |               NULL |                  NULL |
| root              | localhost | NO                 |            0 |                  0 | NULL      |               NULL |                  NULL |
| user1             | %         | YES                |          100 |                  1 | NO        |                 96 |                     0 |
| NULL              | %         | NO                 |            0 |                  0 | NULL      |               NULL |                  NULL |
+-------------------+-----------+--------------------+--------------+--------------------+-----------+--------------------+-----------------------+
7 rows in set (0.00 sec)

Summary

There are multiple ways to monitor MySQL or MariaDB login attempts, but only the Audit Log Filter allows you to specify exactly what you want to log, like only failed logins, for instance. Due to MySQL connection handling behavior, in order to log authentication attempts from undefined hosts, a secure catch-all user account may be needed, though.

As for the TCP scanners, MySQL may not be able to log all such connection attempts, depending on how fast the connection is terminated.

The article was created by a human.

 

The post Auditing Login Attempts in MySQL and MariaDB appeared first on Percona.

Powered by WordPress | Theme: Aeros 2.0 by TheBuckmaker.com