Sales Operations
Kibana + MySQL Integration: Options, Setup, Costs
Need Kibana dashboards from MySQL? Here’s the operator-grade playbook: architectures that work, step-by-step setup with Logstash/CDC, data modeling, and cost control.
You want real-time dashboards from MySQL without buying yet another BI license or adding three new headcount. Kibana is fast, flexible, and great for time-series and operational analytics - but here’s the catch: it doesn’t talk to MySQL directly. You need a pipeline. This guide gives you the architectures that work in production, the trade-offs, and a straightforward implementation path, so you can stand up MySQL → Elasticsearch → Kibana dashboards that leadership actually uses.
Start with the outcome: what do you want from Kibana + MySQL?
Before touching any tooling, define the decision you want to enable. “We need dashboards” is not a requirement. Examples that map cleanly to Kibana’s strengths include tracking daily net revenue across key regions, monitoring product activation events and cohort retention, or watching SLA-related metrics like average resolution time per team and alerting when it drifts.
Kibana excels when you need speed and slice-and-dice on semi-structured, time-stamped data. If your leadership asks for highly relational reporting with many joins, ad hoc pivoting, and strict tabular semantics, a BI tool closer to your warehouse may fit better. If your goal is operational visibility and quick answers with drill-downs, Kibana does that well - once your MySQL data lands in Elasticsearch in a document shape.
That’s why data modeling matters here. Relational rows and foreign keys aren’t a one-to-one fit with documents and fields. You’ll need to pre-join, denormalize, or emit events from the app tier. You’ll see how below.
Can Kibana connect to MySQL directly? Short answer and implications
Short answer: no, not natively. Kibana queries Elasticsearch (or OpenSearch). There’s no “add MySQL data source” button. This isn’t a bug - it’s a design choice. Kibana was built for fast querying over inverted indexes and time-series data, not relational SQL joins.
Implication: you must ship data from MySQL into Elasticsearch. That can be batch (periodic snapshots), incremental (last_updated watermark), or change data capture (near real time). The right path depends on freshness needs, load, and your tolerance for complexity.
There’s also a culture gap. MySQL people think in joins and constraints. Elasticsearch thinks in documents, fields, and relevance. Bridging the two means deciding which MySQL tables to denormalize, how you’ll handle updates and deletes, and what index lifecycle you want to run long-term.
Integration patterns that actually work in production
There are four common patterns that teams use successfully. You can start simple and evolve. The key is to keep your ingestion deterministic and observable, so dashboards don’t drift as data grows.
1) Batch sync with Logstash JDBC input (predictable, simple)
This approach runs on a schedule (say, every 5–15 minutes). Logstash connects to MySQL using the JDBC input, runs a SELECT query, and ships rows into Elasticsearch. You control the SQL and can pre-join tables inside the query, which is ideal for denormalization. You’ll generally include a last_updated or auto-incrementing ID to pull only new/changed rows.
Pros: easy to reason about, minimal moving parts, quick to set up. Works well for analytics that tolerate 1–15 minute latency. Cons: heavy joins in SQL can be slow; you must handle deletes explicitly; large tables need careful pagination and indexing strategy.
When to use: executive or operational dashboards refreshed on short intervals, nightly backfills, and when you own the schema and can add last_updated fields.
2) Near real-time CDC with Debezium + Kafka + Logstash (freshness at scale)
If you need second-level freshness and consistent change capture (inserts, updates, deletes), Debezium can read MySQL binlogs and publish change events to Kafka. Logstash or Kafka Connect then transforms those events and writes to Elasticsearch. You create or update documents in Elasticsearch keyed by a stable ID that maps to your MySQL primary key.
Pros: reliable, low-latency, handles deletes and schema evolution with care. Scales with event volume. Cons: more infra and more to operate (Kafka, connectors), CDC semantics to manage, and a learning curve.
When to use: product analytics, billing/reconciliation views where freshness matters, or when batch windows won’t keep up with writes.
3) Observability via Elastic Agent and Beats (logs, slow queries, audit)
If your goal is MySQL performance visibility - slow query logs, error logs, connections - Elastic Agent or Beats can ship MySQL and system logs straight to Elasticsearch. This doesn’t mirror business tables; it gives operational telemetry to complement your business dashboards.
Pros: turnkey modules, fast time-to-value for DB ops insights. Cons: not a substitute for syncing business data; it won’t power revenue dashboards by itself.
When to use: add this alongside data sync to watch database health and query performance in the same Kibana instance.
4) Emit enriched events from your app (bypass the hardest joins)
Some teams avoid expensive ETL by having the application emit denormalized business events to a queue or directly to Elasticsearch (via an ingest API). For example, when an order is created, the app publishes an “order_placed” event with customer and product attributes flattened in the payload.
Pros: avoids heavy joining later, real-time by design, scales with app. Cons: requires engineering work, event design discipline, and backfill strategy for historical data.
When to use: you control the app, need low latency, and want analytics that mirror user and revenue events tightly.
Data modeling: from relational rows to Elasticsearch documents
Elasticsearch is optimized for documents and time-series queries. The better you shape your data before indexing, the faster your dashboards load and the less you need to maintain. Good models are explicit about time, identity, and granularity.
Decide whether each index represents events (e.g., order events, status changes) or snapshots (e.g., current account state). Events are great for trends and funnels; snapshots are useful for “latest known state” views. You can combine both in dashboards if you keep IDs and timestamps consistent.
Think in denormalization boundaries. Include the fields your dashboards need directly on the document, even if that duplicates data from reference tables. When lookups change (e.g., product category renamed), decide whether events should reflect history or the latest label. That drives whether you join at ingestion time or enrich at query time.
Materialize joins before indexing
MySQL joins are cheap on the database compared to simulating them at query time in Elasticsearch. Use your Logstash SQL to pre-join fact tables to dimensions (customers, products, salespeople) and output a flattened document per analytic unit (e.g., one row per order item with embedded attributes for customer region and product category).
For multi-table dependencies, prefer incremental materialization: select only rows changed since last watermark, and join against static dimensions cached in memory or pulled once per run. If dimensions change frequently, consider a two-step model: index dimensions as small indices and use enrichment processors (ingest node) to stamp fields during bulk loads.
Keep your document size in check. Wide documents with nested arrays can still work, but measure query time and consider breaking into multiple complementary indices if a single document grows unwieldy.
Time-series indices and lifecycle
Create time-based indices like orders-YYYY.MM or orders-YYYY.MM.DD when data volume is high. That enables fast retention, rollover, and tiering. Use Index Lifecycle Management (ILM) to move older shards to warm/cold nodes, shrink, or delete after your retention period. Your Kibana index pattern then targets orders-* with time filtering, which keeps queries fast.
If volume is moderate, monthly indices are fine. If you push millions of docs/day, daily or hourly can help. The right granularity is a function of shard size (ideally tens of GB, not hundreds) and your retention window.
Align index naming with dashboard needs. If executives filter by region every day, consider region-specific indices or a region field with a keyword mapping and pre-filtered index patterns for different personas.
Identity, updates, and deletes
Use a stable document ID equal to your MySQL primary key (or a composite string). That enables idempotent upserts. For batched updates, Logstash can use an action of update with doc_as_upsert true, so the same event won’t duplicate on retries.
For deletes, either publish explicit delete actions (with CDC) or run periodic “tombstone” sweeps: query MySQL for deleted IDs and delete them in Elasticsearch. Another technique is a soft_delete flag and filtering at query time, followed by a weekly purge job.
Index mappings matter. Explicitly set keyword vs text, date formats, and numeric types to avoid runtime field surprises. If you must change mappings later, use reindex into a new index with an alias switch to avoid downtime.
Step-by-step: MySQL → Elasticsearch → Kibana with Logstash JDBC
If you want a straightforward build without Kafka, start here. Below is a practical sequence you can execute in under a day for an initial dashboard, then harden over a week.
1) Prepare MySQL for incremental sync:
- Add a last_updated DATETIME column on your fact table(s) if absent. Populate it from updated_at or create triggers. Index it.
- Ensure each table has a stable primary key. Composite keys are fine; you’ll concatenate them in Logstash as the document ID.
2) Provision Elasticsearch and Kibana:
- Use a managed cluster or self-host. Start with a 3-node setup for resilience if this is production. Define a dedicated ingest node if you expect high daily volumes.
- Create an index template with explicit mappings for your target index. Set appropriate analyzers and keyword fields for dimensions you’ll filter on.
3) Install Logstash and the JDBC driver:
- Install Logstash on a VM close to MySQL and Elasticsearch to reduce latency.
- Add the MySQL JDBC driver to Logstash’s libs directory.
4) Write your Logstash pipeline config:
- Input: jdbc plugin with your connection string, schedule (cron syntax), SQL select with WHERE last_updated > :sql_last_value and ORDER BY last_updated, id for pagination. Set tracking_column to last_updated and use last_run_metadata_path to persist state.
- Filter: ruby or mutate to cast types, build a composite ID if needed, normalize enums (e.g., uppercasing region codes), drop debug fields.
- Output: elasticsearch with action => update, doc_as_upsert => true, index => your-index-YYYY.MM (compute date from event timestamp), document_id => your stable ID.
5) Run initial backfill safely:
- Disable the schedule and run with a bounded time window to validate mappings. Inspect in Kibana’s Discover to make sure fields are correctly typed.
- Backfill in chunks by date range to avoid hammering MySQL. Monitor Elasticsearch ingest rate and heap.
6) Enable the schedule and build dashboards:
- Create an index pattern in Kibana pointing to your indices. Set the time field to your event timestamp.
- Use Lens to create KPIs, trend lines, and breakdowns by your key dimensions. Pin filters and create saved views for each persona.
7) Add alerts and housekeeping:
- Configure alerts for freshness (e.g., if no new docs in 15 minutes). Alert to Slack or email.
- Set ILM policies for rollover and retention. Keep shards to reasonable sizes and monitor with Stack Monitoring.
Real-time sync and backfills without breaking dashboards
You’ll eventually need to reindex, change mappings, or run a backfill. Do it without blanking your dashboards. The trick is using index aliases and versioned indices. Write into a new index version while the alias points to the old one; when ready, atomically swap the alias.
For CDC pipelines, coordinate your consumers during schema changes. Debezium can emit schema change events; ensure your transform layer is tolerant (e.g., treat new fields as optional). Run compatibility tests for mapping changes before shipping to production.
For long backfills, throttle your workers and measure end-to-end latency. If data is late, annotate your dashboards and communicate to stakeholders. Alert on ingestion lag explicitly to avoid misreads in revenue or SLA dashboards.
Build dashboards execs actually use
Good dashboards answer a question in under five seconds. Keep the number of visualizations per view small, with clear KPIs on top and diagnostic breakdowns below. Give each role a dedicated space to avoid filter collisions.
Use Kibana Lens for most visuals. It’s quick, and formulas cover common ratios (conversion rate, AOV, CSAT). Reserve TSVB (Time Series Visual Builder) for more advanced time math or moving averages, and Vega only when you need custom plots.
Make filters obvious. Pre-create saved searches and dashboard-level filters for Region, Plan, Channel, Product Category, and Date Range. Use keyword fields for exact matches and add human-friendly labels where possible.
Lens tips for business metrics
- Prefer cumulative sums for period-to-date metrics like MTD revenue.
- Use percentiles for response times instead of averages; P95 tells a truer story for latency.
- Annotate deployments, pricing changes, or campaigns as markers on key charts for context.
TSVB and formulas for ratios
- Build conversion rate as Orders / Sessions and control time offsets to compare week-over-week.
- For churn or retention, model cohorts as a static dimension and filter TSVB by cohort month to visualize survivorship curves.
- Use series overrides to keep Y-axes consistent across related charts; misaligned axes breed bad decisions.
Alerts and SLO-ish monitoring
- Set alert rules for leading indicators (e.g., checkout errors, payment declines, support backlog). Keep noise low; alert on sustained conditions, not blips.
- Route alerts to the right channel. Revenue alerts to the GM; infrastructure anomalies to engineering. Avoid sending everything to one Slack channel.
- Periodically review alert accuracy. Every false positive taxes attention and degrades trust in the dashboard.
Security, governance, and cost control
Security is not an afterthought, especially if you’re indexing PII. Segment users with roles and spaces, restrict which index patterns each role can query, and mask sensitive fields where possible. Elasticsearch supports field-level security in certain licenses; if you’re on OSS, minimize sensitive data at ingestion.
Map your compliance needs. If GDPR or similar applies, store the minimum needed, tokenize or hash emails (keep a keyed hash if you must join externally), and define deletion workflows that propagate from MySQL to Elasticsearch in a verifiable way.
Cost-wise, model ingestion volume, retention, and query patterns. Elasticsearch costs are driven by storage, compute, and I/O. Time-based indices plus ILM keep storage sane by tiering old data. For traffic spikes, separate ingest from query nodes to protect dashboard latency.
Role-based access and spaces
Use Kibana Spaces to create separate work areas per department or region. Assign roles that limit index access - finance doesn’t need engineering logs, and support doesn’t need customer PII. Keep edit rights to a small group; most users should view only.
Audit access regularly. Track which dashboards are actually used and prune the rest. Simplify navigation; a clean space builds adoption faster than a library of half-used visuals.
Document your data dictionary inside Kibana (Markdown panels on dashboards work) so new users know exactly what each metric means and which filters apply.
PII minimization
Drop raw names and emails unless strictly necessary for a workflow. Use hashed identifiers for user keys. For ad-hoc lookups, maintain a separate, access-controlled tool that can map hashes to real identities when required.
For geo, use region or city codes rather than precise coordinates unless mapping accuracy is critical. For currency, store a normalized currency and exchange rate reference to avoid retroactive changes.
Build a deletion service that, given a user ID, marks records in MySQL and propagates a tombstone to Elasticsearch. Log each deletion for audit.
TCO: hosting, ops, and licenses
Your TCO includes compute for Elasticsearch and Kibana, storage for indices, the ingestion layer (Logstash/Kafka), and ops time. Start modest: one ingest node, two hot data nodes, and S3 (or similar) snapshots. Add warm nodes as your retention grows.
If near real-time is necessary, budget for Kafka and CDC connectors. If not, a single Logstash box can take you far. Automate your ingestion with CI and configuration management so pipelines are reproducible.
For many growth-stage teams, this stack replaces a pricey BI license for operational dashboards and supports alerting that BI usually cannot. If your need is deep ad-hoc SQL analysis, pair this with a lighter BI or warehouse view instead of forcing Kibana to be something it’s not.
Kibana vs Grafana vs Metabase for MySQL reporting
It’s worth a quick comparison so you don’t force-fit a tool. Kibana is excellent once data is in Elasticsearch. Grafana can query MySQL directly and is strong for time-series too. Metabase is great for approachable SQL-based analytics and sharing simple dashboards without much setup.
Choose Kibana if you need speed at scale on event data, rich filtering on denormalized documents, and alerting tightly coupled with your logs and metrics. It’s particularly strong for product and ops analytics where time and cardinality matter.
Choose Grafana if you want to keep MySQL as a data source and you’re already using it for infra metrics. Choose Metabase if your team is SQL-first and your analytics are primarily relational. Many teams run two tools: Kibana for operations and events; Metabase for warehouse/relational reporting.
Implementation plan and pitfalls checklist
Here’s a pragmatic rollout plan that avoids common traps.
- Week 1: Pick 1–2 must-have metrics (e.g., daily paid orders, refund rate). Model the document shape and build a single Logstash pipeline with a last_updated watermark. Backfill one month. Put two dashboards in front of stakeholders.
- Week 2: Add alerts for freshness and SLA thresholds. Implement ILM for indices. Create spaces and roles. Document metric definitions on dashboards.
- Week 3–4: Expand coverage to 4–6 critical metrics. Add CDC if freshness gaps hurt decisions, or partition pipelines if batch windows creep. Start a deletion/tombstone process.
Pitfalls to avoid:
- Over-joining at query time in Elasticsearch. Pre-join in SQL or enrich during ingest.
- Mapping drift. Freeze mappings early; reindex with aliases when you must change them.
- Silent failures. Add logging and alerts for ingestion lag, error rates, and index bloat.
- One giant index. Use time-based indices and keep shards healthy. Monitor query latency and heap.
As your ingestion layer grows, “set and forget” stops working. Put pipelines under version control, test SQL and mappings in staging, and treat data contracts seriously.
Note: if you prefer to automate syncs and alerts with minimal overhead, modern workflow tools like Make or n8n can orchestrate checks, notifications, and housekeeping around your ingestion jobs. When you need more robust orchestration and vendor-neutral pipelines, build a thin control plane and keep operators in the loop.
If you’re wondering whether to involve an agency or hire a team, there’s a practical middle path. Anton Chisliuk · AI Marketing Ops runs as an operator model - one senior builder who ships the stack end-to-end (Kibana, ETL, HubSpot, automation) without the agency tax. Proof matters: for Cleverence (B2B SaaS), the program delivered 0→80K organic visits/month and ~2K inbound leads/month. If you want to see how that operating model works and whether it fits your org, read the about page.
When to add CDC, and when to keep batch
Add CDC when business users change decisions based on hour-to-hour changes and when deletes/updates are frequent enough that batch reconciliation causes confusion. CDC shines for billing, fraud, and product analytics pipelines with high write volumes.
Stick with batch when your data changes slowly, when nightly or 15-minute latency is acceptable, or when you’re testing a new dashboard and don’t want to commit to a Kafka footprint yet. Batch is also easier for teams without dedicated data engineers.
You can hybridize: use batch for bulky facts (orders) and CDC for small, high-velocity updates (order status changes). The key is keeping IDs stable and avoiding double-writes.
Operationalizing: monitoring, incident response, and ownership
Dashboards are only as trustworthy as the pipeline behind them. Establish ownership: who handles ingestion incidents, who approves mapping changes, and who communicates dashboard impacts to stakeholders. Create runbooks for common failures (MySQL timeout, mapping conflicts, Kafka consumer lag).
Build synthetic tests: a canary record in MySQL updated hourly that you expect to see in Kibana within five minutes. Alert if it’s missing. Track p50 and p95 ingestion lag over time and review weekly.
For housekeeping, schedule periodic compaction or reindex of “hot” indices if mappings changed or if field explosion occurred. Keep a changelog and annotate dashboards when meaningfully changing metric definitions.
Real proof: what results look like when ops are tight
Ops-led analytics pay back in decisions, not in pretty charts. When engineering, marketing, and finance stare at the same reliable trend lines, two things happen: faster iteration and fewer “data truth” debates. Adoption increases when dashboards load fast and when alerts are accurate. That’s the outcome you’re buying with Elasticsearch and Kibana.
If you want to see what disciplined marketing ops looks like in outcomes, review the Cleverence case study. From zero to 80K organic visits/month and ~2,000 inbound leads/month didn’t come from dangling a new tool - it came from an operator mindset and consistent systems. Here’s the proof: Cleverence case study.
On the data side, the same rigor applies: ship a minimal pipeline fast, verify with stakeholders, then scale with confidence. Don’t build a cathedral of infrastructure no one uses.
For teams that need orchestration, alerts, and light data plumbing around ingestion, a pragmatic approach is to fold the pipeline into your broader marketing automation workflows, so dashboards and go-to-market systems stay in sync.
Conclusion
Kibana won’t query MySQL directly - and that’s fine. If you define the decisions you want to enable, shape data into documents, and pick the right ingestion pattern (batch JDBC for simplicity, CDC for freshness), you can deliver fast, trustworthy dashboards without committing to an expensive BI stack or a long data-warehouse project.
Start with a single metric, flatten joins before indexing, and keep ownership clear. Use aliases for safe reindexing, alerts for freshness, and ILM for cost control. Treat dashboards like products: iterate with users, retire what’s not used, and don’t tolerate flaky data.
If you want a second set of eyes on architecture and a short path to a working dashboard, book a free Growth Audit - we’ll outline the fastest path from your MySQL to exec-ready Kibana, no agency overhead. Written by Anton Chisliuk.
FAQs
- Does Kibana support MySQL as a data source?
No. Kibana queries Elasticsearch (or OpenSearch). To visualize MySQL data, you must ship it into Elasticsearch via batch (Logstash JDBC), CDC (Debezium + Kafka), or by emitting events from your app.
- What’s the quickest way to try Kibana with MySQL data?
Use Logstash’s JDBC input with a last_updated watermark, ship a small subset (e.g., last 30 days) into a time-based index, and build a simple Lens dashboard. You can have a proof-of-concept in hours.
- How do I handle MySQL deletes in Elasticsearch?
With CDC you can send delete events. In batch mode, run a periodic reconciliation job that checks for missing IDs in MySQL and deletes corresponding Elasticsearch documents, or use a soft_delete flag and purge weekly.
- Should I use one index or time-based indices?
Use time-based indices for moderate to high volume. They make retention, rollover, and tiering easy and keep queries fast. A single index is fine for light volume but becomes unwieldy as data grows.
- Is Elasticsearch overkill if I only need a few dashboards?
If latency needs are low and your metrics are purely relational, a BI tool on top of MySQL might be enough. If you need speed, high-cardinality breakdowns, or alerting integrated with logs/metrics, Elasticsearch + Kibana is a fit.
- How fresh can the data be?
Batch with Logstash can run every few minutes reliably. CDC with Debezium + Kafka can be near real-time (seconds). Pick based on decision latency needs, not vanity freshness.
- What about joins? Can Kibana do them?
Kibana doesn’t do relational joins. Elasticsearch has limited join-like features, but for performance and simplicity, materialize joins before indexing (SQL in Logstash) or enrich at ingest with lookup processors.
- How much does this cost to run?
Costs depend on data volume, retention, and query load. A modest 3–4 node Elasticsearch cluster and one Logstash box can handle many use cases. Add warm storage and CDC infra only if your needs demand it.
- Is OpenSearch Dashboards an alternative?
Yes. OpenSearch Dashboards is compatible with OpenSearch (an Elasticsearch fork). Integration patterns from MySQL are similar: batch via Logstash or CDC via connectors into OpenSearch, then visualize.
Written by
Anton Chisliuk
Founder & Lead Operator · AI Marketing Operator
Anton Chisliuk is a GTM Engineer and Marketing Systems Architect. He built Cleverence's AI-native revenue OS (88 Make blueprints, MCP hub, 0→200K organic, 2.2K leads/mo) and now delivers outsourced GTM Engineering — CRM, automation, SEO, outbound — for growth-stage businesses via aimrktops.com.
About Anton →Ready to fix this — for real?
Book a free Growth Audit. No sales deck — a 30-minute conversation about your pipeline, stack, and what to ship first.