Introduction
We've all stared at a Grafana dashboard that told us nothing useful, or spent ten minutes hunting for the metric we needed in a sea of panels. Common Grafana mistakes: real-world lessons and examples stem from rushing deployment, poor planning, or simply not having thought through how a team actually uses monitoring. After running dashboards across trading platforms, e-commerce systems, and SaaS products, we've seen patterns repeat. The problems aren't technical failures—they're communication breakdowns between what we measure and what we need to see.
This post walks through the most costly mistakes we've caught in production, what they cost us, and how to avoid them.
Too Many Panels on a Single Dashboard
A dashboard with thirty panels sounds comprehensive until you're on call at 3 AM and can't find the metric that matters. We once inherited a Grafana instance with a "complete system overview" dashboard that had 47 panels. Response time sat next to disk I/O next to database pool exhaustion next to third-party API latency. Nothing was related, and every alert fired in concert.
The problem: our brains can't parse that much information quickly. A good dashboard should answer one or two focused questions. "Is the system healthy?" or "Why is checkout slow?" Not both at once.
Real-world scenario
An e-commerce platform had a single dashboard for the entire checkout flow. It contained:
- Request rates for six different services
- Error rates for those same services
- Database connection pool metrics
- Cache hit ratios
- Payment gateway latency
- Third-party shipping API response times
- Customer browser metrics
- Infrastructure CPU, memory, and disk
When a customer reported slow checkouts, the on-call engineer had to scroll through dozens of panels to narrow down whether the issue was in the payment service, the shipping integration, or the browser. By the time they figured it out, the incident had been running for twenty minutes.
The fix: dashboard per concern
Split that single dashboard into:
- Checkout Health: request rate, error rate, and p99 latency for the checkout service only
- Payment Flow: payment gateway latency, success rate, and failure reasons
- Dependencies: shipping API, database pool, cache behavior
- Infrastructure: CPU, memory, disk across the platform
Now an on-call engineer can jump to "Checkout Health" and immediately see the problem. If checkout latency is high but error rate is normal, they navigate to "Payment Flow." The dashboard hierarchy itself becomes the troubleshooting tree.
Practical limit
We keep dashboards to 6–9 panels maximum. Each panel should make sense without reading a legend. If you need to explain what a panel does, it's probably not specific enough.
Mixed Units on One Axis
This one hurts because the mistake is easy to make and hard to spot. You add CPU percentage, memory in gigabytes, and disk I/O in operations per second to the same graph. Grafana will plot all three, but the axis scale becomes meaningless. A spike in disk I/O at 5,000 ops/sec looks tiny next to memory at 60 GB, and CPU at 80%. You miss the actual problem.
Real-world scenario
A trading platform plotted three metrics on a single graph:
- Exchange latency (milliseconds)
- Order volume (count per second)
- Market volatility (basis points)
During a market spike, the trader on watch saw a graph that looked flat because volatility (in basis points, 0–100 range) dwarfed the y-axis, hiding the latency spike (0–500 ms) and volume surge (0–10,000 orders/sec). By the time they switched to separate panels, trades had queued for thirty seconds.
The fix: one unit per panel
Create three separate panels:
- Exchange Latency (y-axis: milliseconds)
- Order Throughput (y-axis: orders/sec)
- Market Volatility (y-axis: basis points)
Link them so they scroll and zoom together, but let each scale to its own range. Now a 50% spike in latency appears as an actual spike on its panel.
Grafana configuration example
Use separate series with different y-axes (right axis for non-primary metrics):
panels:
- title: "Order Latency vs Throughput"
targets:
- expr: 'histogram_quantile(0.99, order_latency_ms)'
legendFormat: "p99 Latency (ms)"
yaxisside: left
- expr: 'rate(orders_total[1m])'
legendFormat: "Orders/sec"
yaxisside: right
Better yet, use two adjacent panels side by side. They're easier to scan and leave no room for axis confusion.
No Dashboard Variables for Different Environments
You build a beautiful dashboard for production, then realize it only shows prod data. To monitor staging, you copy the dashboard, rename it, and hardcode staging values. Now you have two dashboards to maintain. When you update one, you forget the other. Eventually they diverge and nobody trusts either.
Real-world scenario
A SaaS company had separate dashboards for production, staging, and development. When they added a new metric to track subscription renewals, the engineer updated prod and staging but forgot dev. Three weeks later, a dev incident went unnoticed because the dev dashboard was missing the critical signal. The company had been flying blind on dev monitoring.
Worse, they'd accidentally hardcoded database names and service endpoints in each dashboard. When they migrated the staging database, the staging dashboard broke silently—queries returned empty.
The fix: template variables
Use Grafana variables to parameterize environment, service name, and pod namespace:
dashboard:
templating:
list:
- name: environment
type: query
datasource: Prometheus
query: 'label_values(up, env)'
current:
value: "prod"
- name: service
type: query
datasource: Prometheus
query: 'label_values(up{env="$environment"}, service)'
- name: pod_namespace
type: query
datasource: Prometheus
query: 'label_values(up{env="$environment", service="$service"}, namespace)'
Now your metrics query becomes:
targets:
- expr: 'rate(http_requests_total{env="$environment", service="$service", namespace="$pod_namespace"}[5m])'
A single dashboard works for all environments. You update it once. Variables cascade (pod_namespace options depend on the selected service, which depends on environment). On-call engineers can click the environment dropdown and instantly switch context.
Pro tip: save per-environment views
Let engineers bookmark URLs with variables pre-filled:
https://grafana.example.com/d/abc123/dashboard?var-environment=prod&var-service=checkoutEach team can have a bookmarked link that defaults to their environment and service.
Dashboards Nobody Owns
The worst dashboards are the ones with no owner. They accumulate panels nobody remembers adding, queries that broke when a metric changed, and alerts nobody reads anymore. Nobody updates them. Nobody deletes them. They become digital clutter.
Real-world scenario
A ride-hailing platform had a dashboard called "Platform Metrics" created by an engineer who left two years ago. It had 34 panels. When Prometheus was upgraded and label cardinality changed, some queries returned no data. For months, the team didn't notice because nobody actually used that dashboard. The on-call runbook pointed to it, but on-call engineers had learned to ignore it and use newer, more reliable dashboards instead. New engineers wasted hours understanding why it was broken.
The real cost: team trust erodes. If one dashboard is stale, engineers assume all dashboards might be. They start keeping their own spreadsheets and scripts.
The fix: ownership and review cycles
Assign an owner to every dashboard. In Grafana Enterprise or with annotations, add metadata:
dashboard:
title: "Checkout Service Monitoring"
description: "Owner: @payment-platform-team. Last reviewed: 2024-01-15. Review frequency: quarterly."
tags:
- owner:payment-platform-team
- review:quarterly
Establish a review cycle. Every quarter, the owner:
- Verifies all queries return data
- Checks that alerts actually fire
- Removes unused panels
- Updates the "last reviewed" timestamp
Use Grafana folders to organize by team and delete old, unreviewed dashboards after six months of inactivity.
Consider a light governance approach: a simple Grafana dashboard that lists all dashboards, their owners, and review status. Teams can see at a glance which dashboards are maintained and which are stale.
Common Mistakes Summary
| Mistake | Cost | Fix |
|---|---|---|
| Too many panels | Slow incident response, confusion during triage | Split into focused dashboards (6–9 panels each) |
| Mixed units on one axis | Metrics hide behind scale, miss real spikes | Separate panels per unit, or use dual y-axes |
| No environment variables | Dashboard duplication, divergence, maintenance burden | Parameterize with Grafana template variables |
| No ownership | Stale queries, eroded trust, wasted triage time | Assign owner, quarterly review, archive unused |
Key Takeaways
- Dashboard design is communication design. A dashboard should answer one question clearly, not twenty ambiguously.
- Normalize axes. Never mix units on the same panel. Keep scales honest so spikes are actually visible.
- Use variables for environment and service context. A single parameterized dashboard beats ten hardcoded copies.
- Assign ownership and review regularly. Stale dashboards break trust. Set a review cadence and archive anything unused after six months.
- Keep panels count low. If an engineer can't scan the entire dashboard in under ten seconds, it's too complex.
- Test queries against actual alerts. A beautiful dashboard is useless if queries return empty or alerts never fire.
- Link related dashboards. Use breadcrumbs or a dashboard index so on-call engineers can navigate from system health to service details to infrastructure in one click.
These mistakes don't require advanced Grafana features to fix—they need clear thinking about what the team actually needs to see and who's responsible for keeping it accurate. Start with a focused use case (e.g., "production incident triage for checkout"), design for that scenario, then expand. Your team will thank you at 3 AM.






Comments
Loading comments…