
Run MySQL on Kubernetes: Step-by-Step Deployment
Learn how to deploy MySQL on Kubernetes with this step-by-step guide. Optimize your database management using Kubernetes' scalability and resilience features.
Managing databases outside of Kubernetes creates operational silos and scattered tooling. Platform teams often end up managing separate deployment pipelines, monitoring systems, and access controls, which adds complexity and increases the likelihood of misconfigurations. Running MySQL directly on Kubernetes fixes this by bringing your data layer into the same infrastructure as your applications. When you manage it declaratively, MySQL becomes part of your GitOps workflow—version-controlled, auditable, and deployed consistently. This guide shows you how to deploy a production-ready MySQL instance on Kubernetes, so you can unify your operations, streamline observability, and improve security across your entire stack.
Unified Cloud Orchestration for Kubernetes
Manage Kubernetes at scale through a single, enterprise-ready platform.
Key takeaways:
- Prioritize stateful prerequisites for reliability: Before deploying, ensure your cluster is ready for stateful workloads. This means having a solid storage strategy with Persistent Volumes, using StatefulSets for stable pod identity, and managing credentials securely with Kubernetes Secrets.
- Use a MySQL operator for automated high availability: Move beyond a single-instance deployment by using an operator to manage a high-availability cluster. This automates complex tasks like replication, failover, and backups, which are essential for production-grade resilience.
- Streamline fleet-wide operations with a unified platform: Managing MySQL at scale requires consistency. Use a platform like Plural to enforce best practices through GitOps, centralize monitoring in a single dashboard, and declaratively manage infrastructure to eliminate configuration drift across your entire fleet.
Why Run MySQL on Kubernetes?
Running stateful applications like databases on Kubernetes has evolved from a complex challenge into a common best practice. Early concerns—especially around container ephemerality and storage persistence—were valid. However, with the maturity of Kubernetes primitives such as StatefulSets, PersistentVolumeClaims, and StorageClasses, combined with a thriving ecosystem of MySQL Operators, it’s now both feasible and beneficial to run databases like MySQL directly within your Kubernetes clusters.
This shift enables platform teams to unify their infrastructure under a single control plane. Rather than managing databases with isolated tools and workflows, you can treat MySQL as a declarative Kubernetes resource. This integration aligns your database lifecycle with your GitOps workflows, simplifying operations, reducing tool sprawl, and enabling consistent policies for deployment, observability, and security across your entire stack—from front-end to data layer.
What is MySQL?
MySQL is a leading open-source relational database management system (RDBMS) that uses SQL (Structured Query Language) for managing structured data. Known for its performance, reliability, and strong community ecosystem, it powers a wide range of workloads—from personal projects to large-scale enterprise applications. MySQL supports both OLTP (Online Transaction Processing) and analytical workloads, making it a versatile choice across industries.
As a stateful component, MySQL requires careful handling of data persistence, backups, and configuration. Running it on Kubernetes demands attention to its lifecycle, but modern tooling makes this much easier to automate and scale.
Key Benefits of Running MySQL on Kubernetes
Deploying MySQL on Kubernetes offers operational consistency, automation, and resilience by leveraging the orchestration capabilities of the platform. Here are the core advantages:
- Scalability and Resource Efficiency
Kubernetes enables dynamic scaling of MySQL instances by tuning resource requests or adding replicas. Its scheduler efficiently distributes workloads across nodes, optimizing hardware utilization. - High Availability and Resilience
Kubernetes restarts failed pods automatically. For production-grade deployments, MySQL Operators support clustering and automated failover, often based on MySQL InnoDB Cluster or Group Replication, ensuring minimal downtime. - Simplified Lifecycle Management
Operators encapsulate operational knowledge, automating tasks like provisioning, upgrades, backups, and user management. With tools like Plural, you can define and deploy MySQL as code—including persistent volumes and networking—ensuring repeatable, version-controlled infrastructure across environments.
Prepare for Deployment
Deploying a stateful application like MySQL on Kubernetes requires careful preparation. Unlike stateless services, databases introduce critical requirements around data persistence, networking, and configuration consistency. Skipping these fundamentals often leads to issues such as data loss, connectivity failures, and unpredictable behavior across environments.
By verifying prerequisites and setting up the right tools in advance, you lay the groundwork for a stable, production-ready deployment that can scale confidently, saving hours of troubleshooting later.
Review Kubernetes Prerequisites
Before anything else, ensure you have a running Kubernetes cluster and that kubectl
is installed and properly configured with the right context using:
kubectl config use-context your-cluster-name
Because MySQL is stateful, data persistence is essential. Kubernetes handles this through Persistent Volumes (PVs), which retain data across pod restarts. The best practice is to use a StorageClass for dynamic provisioning, allowing Kubernetes to automatically create PVs when a PersistentVolumeClaim (PVC) is requested by a pod.
If your cluster lacks dynamic provisioning support (common in some on-prem setups), you’ll need to manually provision PVs—a process that doesn’t scale well and introduces operational risk. Verifying this setup early is crucial for ensuring data integrity.
Set Up Your Environment and Tools
MySQL deployments in Kubernetes are typically defined with YAML manifests. You can apply these using:
kubectl apply -f mysql-deployment.yaml
However, for complex applications like MySQL, using Helm is often a better approach. Helm charts package all the required Kubernetes resources—Deployments, Services, PVCs, and ConfigMaps—into a single, configurable, versioned bundle. This simplifies installations, upgrades, and rollbacks.
For organizations operating across multiple clusters or environments, manual kubectl
or Helm usage quickly becomes error-prone. This is where GitOps platforms offer a significant advantage. With Plural CD, you can define your MySQL deployment declaratively in a Git repository and manage it with a GitOps workflow. Every change becomes a version-controlled commit, automatically synced across environments.
Plural also provisions required infrastructure components like volumes, secrets, and networking through reusable Plural Stacks, ensuring consistency and eliminating drift.
Deploy MySQL on Kubernetes: A Step-by-Step Guide
Deploying a stateful application like MySQL on Kubernetes requires careful setup of storage, networking, and security. You'll define each component using declarative YAML files and typically apply them using kubectl
. While this is manageable for single deployments, scaling across multiple clusters can lead to configuration drift and operational overhead.
This guide walks through deploying a single-instance MySQL database on Kubernetes. For production or multi-cluster environments, tools like Plural streamline this process using a GitOps-based workflow. With Plural Stacks, you can define infrastructure and application resources declaratively, ensuring consistency and compliance across environments.
Step 1: Create Persistent Volumes and Claims
MySQL requires persistent storage so that data survives pod restarts and rescheduling. Kubernetes handles this through PersistentVolumes (PVs) and PersistentVolumeClaims (PVCs).
A PV represents storage provisioned by the cluster, while a PVC is a request for that storage from an application. In most cloud environments, PVCs trigger dynamic provisioning via a StorageClass, allowing Kubernetes to create PVs automatically.
Here’s a minimal PVC definition:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
Once applied, Kubernetes binds this PVC to an appropriate PV, abstracting away the underlying storage backend.
Step 2: Configure the MySQL Deployment and Service
With storage ready, you can deploy the MySQL application using a Deployment
object that defines the container image, volume mounts, and environment variables.
Example snippet:
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-storage
persistentVolumeClaim:
claimName: mysql-pvc
To expose MySQL to other services in the cluster, create a Kubernetes Service that provides stable DNS and IP routing:
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
selector:
app: mysql
clusterIP: None # Use for StatefulSets or headless services if needed
Apply both manifests using:
kubectl apply -f mysql-deployment.yaml
kubectl apply -f mysql-service.yaml
Step 3: Implement Secret Management
Avoid hardcoding credentials directly into deployment manifests. Instead, use Kubernetes Secrets to securely inject sensitive data such as database passwords.
Create the secret:
kubectl create secret generic mysql-secret \
--from-literal=password='your-root-password'
Then reference it in your Deployment
YAML as shown earlier. This keeps secrets out of version control and ensures they're only accessible at runtime.
For multi-cluster and enterprise deployments, Plural CD enhances this approach by managing secrets and application configs through secure, auditable pipelines. Role-based access controls and Git-based audit logs ensure that only authorized services and users can access sensitive data.
Manage MySQL in Kubernetes: Best Practices
Deploying MySQL on Kubernetes is only the first step. Running it reliably in production requires a disciplined operational strategy that addresses storage durability, performance monitoring, and disaster recovery. Unlike stateless applications, databases maintain persistent state—making them more sensitive to misconfigurations, data loss, and performance bottlenecks. Simply applying a manifest is not enough; you need to manage the entire lifecycle deliberately.
The following best practices will help transform your MySQL deployment from a proof-of-concept into a production-grade, resilient service.
Optimize Data Storage and Persistence
Data durability is critical for databases. In Kubernetes, PersistentVolumes (PVs) and PersistentVolumeClaims (PVCs) decouple storage from pod lifecycle, allowing your MySQL pods to safely restart or reschedule without data loss.
For production-grade MySQL, use a StatefulSet instead of a Deployment. StatefulSets provide:
- Stable, unique network identifiers (hostnames)
- Ordered deployment and scaling
- Persistent volume binding tied to pod identity
These features are essential for clustered or replicated MySQL setups and prevent erratic pod behavior during restarts or upgrades.
If your cluster supports dynamic provisioning via a StorageClass, PVCs can request storage that Kubernetes provisions automatically, reducing manual intervention and improving reliability.
Monitor and Tune Performance
Visibility is essential for maintaining performance and preventing outages. Integrate Prometheus for collecting metrics and Grafana for dashboards to monitor key MySQL indicators such as:
- Query latency and throughput
- Active connections
- Disk I/O and buffer pool usage
- CPU and memory consumption
Export metrics from MySQL using exporters like mysqld_exporter and scrape them via Prometheus. Set up Grafana alerts for threshold violations to catch issues before they impact users.
With Plural, you can centralize monitoring across all your Kubernetes clusters. This single-pane-of-glass approach correlates MySQL performance with cluster health, making it easier to pinpoint bottlenecks—whether they originate in the application, the infrastructure, or the database layer.
Plan Your Backup and Recovery Strategy
Persistent storage is not a backup. A production MySQL deployment requires:
- Scheduled, point-in-time backups
- Tested restore procedures
- Retention policies aligned with compliance or business needs
The MySQL Operator is purpose-built for Kubernetes and automates backups, restores, and cluster lifecycle tasks. It supports declarative backup policies, which can be versioned and audited in Git.
For example, you can define:
apiVersion: mysql.oracle.com/v1
kind: BackupSchedule
spec:
schedule: "0 */6 * * *"
backupProfile: my-profile
retention: 7
Using Plural CD, you can manage these configurations declaratively via GitOps, ensuring backup policies are applied consistently across all MySQL instances in your fleet. This eliminates configuration drift and gives you full visibility and traceability over your disaster recovery strategy.
Scale MySQL for High Availability
Running a single MySQL instance introduces a single point of failure. In any production system, high availability is essential—when your database goes down, so does your application. To ensure resilience and scalability, you need a robust deployment strategy that supports failover, load distribution, and growth. This starts with understanding the differences between vertical and horizontal scaling, and choosing the right replication or clustering method to match.
While Kubernetes offers the foundational building blocks for resilient systems, the architecture you build on top determines your success. A single-instance deployment might be quick to launch but lacks the redundancy needed for production workloads. A distributed MySQL architecture mitigates downtime risks and improves performance by spreading the load across multiple nodes.
Compare Scaling Approaches: Horizontal vs. Vertical
When increasing database capacity, you have two primary strategies:
- Vertical Scaling: Also known as scaling up, this involves adding more CPU, RAM, or disk to an existing MySQL pod. While simple to implement, it has physical limits and may require downtime during upgrades. It also doesn't address availability concerns.
- Horizontal Scaling: This approach—scaling out—involves running multiple MySQL instances to distribute workloads. It's the preferred method for high availability. Kubernetes supports this model using StatefulSets and Persistent Volume Claims, enabling you to maintain stable network identities and persistent storage across pod restarts or node failures.
Horizontal scaling is essential for eliminating single points of failure and enabling your database to grow with demand.
Implement Replication and Clustering
To scale MySQL horizontally, implement replication or clustering:
- Primary-Replica Replication: A straightforward approach where the primary node handles writes and replicas serve read traffic. This offloads query load but doesn’t provide automated failover.
- MySQL Group Replication: Offers multi-primary clustering with automatic failover and consistency guarantees. This setup improves both resilience and write throughput in production environments.
The easiest way to manage replication and clustering in Kubernetes is through the MySQL Operator by Oracle. It automates the lifecycle of a MySQL InnoDB Cluster, including configuration, scaling, backups, and upgrades. The operator handles the complexity of setting up Group Replication within StatefulSets, ensuring high availability and consistency.
With Plural, you can standardize the deployment and management of MySQL clusters across multiple environments using a GitOps workflow. This includes managing the MySQL Operator itself, along with backup policies, monitoring integrations, and security configurations—all from a single control plane.
Troubleshoot Advanced Configurations
Running a stateful application like MySQL on a dynamic platform like Kubernetes presents distinct challenges. Out-of-the-box configurations are rarely sufficient for production, and diagnosing performance issues often requires a deep understanding of both MySQL and Kubernetes internals. Most issues stem from misconfigured storage, networking, or resource allocations.
Effective troubleshooting starts with a systematic approach—understanding how to apply custom settings, identify resource bottlenecks, and tune performance. It requires going beyond basic deployment YAMLs and into areas like resource requests, pod eviction policies, and security contexts. For instance, under-provisioned resources can lead to inconsistent performance or unexpected pod evictions. Proactively addressing these areas helps ensure a resilient, high-performing MySQL deployment.
Plural simplifies this process with a centralized dashboard that surfaces configuration issues and resource health across your entire fleet, making it easier to detect and resolve problems before they affect production workloads.
Apply Custom MySQL Settings
To optimize MySQL for your workload, you'll often need to customize its configuration via the my.cnf
file. In Kubernetes, the standard practice is to store this file in a ConfigMap and mount it into the MySQL container. This keeps your configuration declarative and version-controlled.
Your full deployment typically includes:
- A Secret for database credentials
- PersistentVolume and PersistentVolumeClaim for durable storage
- A StatefulSet or Deployment for pod orchestration
- A Service for stable network access
While kubectl apply
works well for simple setups, managing these components at scale—especially across clusters—can be complex. That’s where Infrastructure as Code (IaC) becomes vital. Plural’s Stacks feature enables GitOps-style deployment of your YAML and Terraform files. Each commit triggers automated updates to the target clusters, ensuring reproducibility and auditability across environments.
Resolve Common Issues and Bottlenecks
Many MySQL issues in Kubernetes environments stem from a handful of common missteps:
- Misconfigured resource requests and limits
- Inadequate monitoring and logging
- Incorrect Quality of Service (QoS) settings
- Storage mismanagement
One critical but often overlooked configuration is the QoS class of your MySQL pods. To ensure predictable performance and prevent eviction during node pressure, you should match the CPU and memory requests exactly to their limits. This ensures the pod receives the Guaranteed QoS class—the most stable option for stateful applications.
Diagnosing issues requires real-time visibility into metrics and logs. Tools like kubectl top or Prometheus can help, but they often require setup and maintenance.
Plural provides a built-in Kubernetes dashboard that consolidates:
- Pod and node metrics
- Persistent volume performance
- Container logs and event timelines
This single-pane-of-glass visibility enables you to quickly identify and resolve performance bottlenecks, misconfigurations, or hardware resource contention—before they escalate into outages.
Secure and Monitor Your MySQL Deployment
Deploying MySQL on Kubernetes is just the beginning. For a production-grade deployment, you must ensure robust security, continuous monitoring, and comprehensive logging. These components work together to deliver a MySQL service that’s not only performant, but also stable and secure under real-world conditions.
Implement Network Policies and Access Control
By default, Kubernetes allows unrestricted communication between all pods, posing a serious security risk to your MySQL database. To lock down access:
- Define a
NetworkPolicy
to restrict ingress traffic. For example, allow only specific application pods to connect to your MySQL pods on port3306
. - Use Kubernetes RBAC (Role-Based Access Control) to manage who can access Kubernetes resources such as
Secrets
,PersistentVolumeClaims
, and the MySQLStatefulSet
itself.
Plural simplifies this with centralized RBAC management, allowing you to define policies once and enforce them across all clusters. It also integrates with your existing identity provider (like Okta, Azure AD, or Google Workspace), making it easy to assign roles and permissions to teams and users.
Set Up Comprehensive Monitoring
Observability is essential for ensuring that MySQL remains performant under load and resilient to failure.
In most Kubernetes environments, monitoring is handled using:
- Prometheus to collect metrics
- Grafana to visualize them
You should track key MySQL and container metrics, such as:
- Query latency and throughput
- Active connections and thread utilization
- Buffer pool hit rate and usage
- Container CPU and memory usage
- Disk IOPS and persistent volume latency
However, managing this stack manually across multiple clusters can be resource-intensive. Plural integrates monitoring into its platform by default, giving you a centralized dashboard that provides real-time metrics and health status for all your MySQL instances—across all clusters. This single pane of glass helps you proactively detect slow queries, resource contention, or impending failures before they degrade user experience.
Implement Effective Logging
Logging is critical for debugging, auditing, and performance tuning.
Best practices for logging MySQL on Kubernetes include:
- Configuring MySQL to log to
stdout
andstderr
so logs are captured by the container runtime. - Running a cluster-level log collector like Fluent Bit, Fluentd, or Vector to ship logs to a backend like Elasticsearch, Loki, or OpenSearch.
This approach creates a centralized, searchable archive of all MySQL logs, but accessing and interpreting these logs can still be cumbersome, especially at scale.
Plural’s embedded logging tools eliminate that friction. You can view logs directly in the dashboard—no need to juggle kubeconfig
files or kubectl logs
. This makes it faster to debug issues like failed startup probes, connection errors, or slow queries right from the UI.
Streamline MySQL on Kubernetes with Plural
While deploying and managing MySQL on Kubernetes offers significant benefits, the operational overhead can be substantial. Manually configuring operators, managing persistent storage across a fleet of clusters, and setting up robust monitoring for each instance requires deep expertise and significant engineering effort. This is where a unified platform can make a material difference. Plural provides the tools to automate these complex workflows, turning a challenging infrastructure project into a repeatable, scalable process.
Simplify Deployment and Management
Deploying MySQL on Kubernetes often involves using an operator to automate lifecycle tasks like setup, maintenance, and backups. Plural simplifies this by allowing you to deploy pre-vetted MySQL operators from our application catalog with just a few clicks. Using Plural Stacks, you can declaratively manage all the necessary infrastructure-as-code, such as persistent volume configurations, ensuring consistency across every deployment. Once configured, our GitOps-based CD automatically syncs any changes from your repository to the target clusters. This means your team can manage the entire MySQL lifecycle through version-controlled pull requests, reducing manual intervention and the risk of configuration drift.
Enhance Monitoring and Observability
Effective monitoring is critical for maintaining the performance and reliability of your MySQL databases. Plural helps you establish comprehensive observability by integrating with standard tools like Prometheus and Grafana, which can be deployed directly through our platform. More importantly, Plural consolidates all this information into a single-pane-of-glass console. Instead of switching between different tools, your team gets a unified view of database performance across your entire Kubernetes fleet. For direct troubleshooting, the embedded Kubernetes dashboard provides secure, SSO-integrated access to check pod logs or resource utilization without needing to manage individual kubeconfigs, streamlining the entire monitoring and remediation workflow.
Related Articles
- Kubernetes StatefulSet: The Ultimate Guide (2024)
- Kubernetes StatefulSet Pod Persistence: A Deep Dive
- Kubernetes Management: A Comprehensive Guide for 2025
- Deep Dive into Kubernetes Components
- Practical Deep Dive into Bare Metal Kubernetes
Unified Cloud Orchestration for Kubernetes
Manage Kubernetes at scale through a single, enterprise-ready platform.
Frequently Asked Questions
Isn't it simpler to use a managed database service instead of running MySQL on Kubernetes? Managed database services are a great choice for simplicity, but running MySQL on Kubernetes provides a unified operational model for your entire stack. It allows you to manage your database using the same declarative GitOps workflows, monitoring tools, and security policies that you use for your applications. This consolidation reduces tool sprawl and operational overhead. With a platform like Plural, you can automate the deployment and management of MySQL operators, giving you benefits like automated backups and failover while keeping everything within your own Kubernetes environment.
The post mentions StatefulSets. Why can't I just use a standard Deployment with a Persistent Volume? While a Deployment with a PersistentVolumeClaim (PVC) will preserve your data, it lacks the stable identity required for a database. StatefulSets provide critical guarantees that Deployments do not, such as unique, predictable network hostnames (e.g., mysql-0
, mysql-1
) and persistent storage that always reattaches to the same pod identity after a restart. This stability is essential for database clustering and replication, where nodes must be able to reliably discover and communicate with each other.
What is the single most important step to secure a MySQL deployment on Kubernetes? While managing secrets and RBAC is vital, implementing NetworkPolicies is arguably the most critical first step. By default, Kubernetes networking is open, allowing all pods to communicate with each other. A NetworkPolicy acts as a firewall at the pod level, allowing you to write rules that explicitly define which applications are allowed to connect to your MySQL instance. This dramatically reduces the attack surface by ensuring that only authorized services can access your database.
How do I achieve true high availability for MySQL in production? Is primary-replica replication enough? Primary-replica replication is a good start for scaling read traffic, but it does not provide the automatic failover needed for true high availability. For that, you need a clustering solution like MySQL Group Replication, which creates a fault-tolerant group of servers that can automatically elect a new primary if the current one fails. The most effective way to manage this on Kubernetes is with a MySQL Operator, which automates the entire lifecycle of the cluster, from setup to failover and backups.
How does Plural specifically help with managing MySQL across many clusters? Plural streamlines the entire process by providing a unified control plane for your Kubernetes fleet. You can use Plural Stacks to declaratively define and provision the necessary infrastructure, like persistent storage, as code. Then, using Plural CD, you can deploy the MySQL Operator and its configurations via a consistent GitOps workflow to all your clusters. Finally, our single-pane-of-glass console offers centralized observability and a secure, embedded Kubernetes dashboard to monitor performance and troubleshoot issues without juggling credentials or tools.
Newsletter
Join the newsletter to receive the latest updates in your inbox.