Why Your Grafana Dashboard Times Out: Delegating Query Limits to the Data Source
Grafana delegates query result limits to your data source. Learn how explicit LIMIT clauses, deterministic ordering, and provisioning settings prevent high-cardinality dashboard timeouts.
14 Feb 2026, 09:52 UTC

The problem is rarely Grafana itself
When a dashboard that worked yesterday starts spinning today, the instinct is to blame the visualization layer. More often, a panel is asking a data source for an unbounded result set—every row matching a filter, with no ceiling—and both the backend database and your browser tab are paying the price. The useful takeaway is this: Grafana does not paginate for you. It delegates result limiting to the data source's native query parameters, which means the boundary must be configured explicitly, either in the query text, the panel options, or the dashboard JSON.
Grafana is a query proxy, not a pagination engine
Grafana builds a query, sends it to the configured data source, and renders whatever comes back. For data sources that support SQL-style pagination—PostgreSQL, MySQL, InfluxDB, and OpenTSDB among them—Grafana can pass a LIMIT clause and an OFFSET through to the backend. In the Explore view and in template variable queries, the limit and offset fields map directly to those native capabilities. If the data source supports the clause, Grafana adds it; if it does not, Grafana cannot enforce a row limit on its own.
Prometheus is a useful counterexample. It has no SQL LIMIT statement. Cardinality control there happens through query design, metric relabeling, and Grafana's own maxDataPoints setting, not through a LIMIT clause sent to the server. Assuming every data source behaves like PostgreSQL is a common source of confusion.
| Data source type | Native limit support | Where Grafana enforces it |
|---|---|---|
| PostgreSQL / MySQL | LIMIT / OFFSET in SQL | Query editor and panel JSON |
| InfluxDB | LIMIT in Flux or InfluxQL | Query editor |
| Prometheus | No SQL LIMIT | maxDataPoints and query design |
Worked example: explicit limits on a PostgreSQL panel
Consider a panel that queries an application metrics table. Without a limit, the query might scan millions of rows and return them all to the browser. The fix is to make the boundary explicit in the SQL and to make the ordering deterministic. Run this in the Grafana panel query editor for your PostgreSQL data source:
SELECT time, value, host
FROM app_metrics
WHERE time > $__timeFrom() AND time < $__timeTo()
ORDER BY time DESC
LIMIT 500;
Two details matter here. First, the LIMIT clause caps the result set at the data source, reducing memory pressure on both the database and Grafana. Second, ORDER BY time DESC makes the result deterministic. Without an explicit ordering, LIMIT and OFFSET return an arbitrary subset, which means the same panel can show different rows on each refresh—a subtle bug that looks like data loss.
You can also set a ceiling in the panel JSON so provisioned dashboards stay consistent. Changing dashboard JSON requires Editor or Admin permissions on the dashboard, and your role must have Query permissions on the data source:
{
"maxDataPoints": 500
}
To verify what Grafana actually sends, open your browser's developer tools, select the Network tab, and inspect the request to /api/ds/query. You should see the limit and offset parameters reflected in the request payload. If they are missing, the panel is not applying the constraint you expect.
The repeater and provisioning override
Panel repeaters and template variables multiply query volume. A table panel repeated over 50 host variables, each with LIMIT 500, asks the data source for 25,000 rows. That may still be acceptable, but it is a deliberate choice rather than an accident. Template variables that query the data source for dropdown values also need explicit limits; otherwise, a variable with thousands of possible values will fetch all of them to populate the dropdown.
Dashboard provisioning introduces a similar risk: a JSON model or the provisioning API can override query editor defaults, so a limit that looks correct in the UI may not survive a redeploy. After upgrading Grafana or changing data source connection settings, re-check your dashboards. Default limit behaviors and query option handling can shift between versions, and a regression here often shows up as intermittent timeouts rather than a hard error.
Trade-offs: memory safety versus completeness
The trade-off is between protecting the browser and hiding data. A lower limit reduces memory footprint, but it can truncate a series right where the interesting anomaly lives. If you need deterministic pagination across pages, you must pair LIMIT with OFFSET and a stable ORDER BY, which adds sorting cost to the query. For high-cardinality time series, it is often better to aggregate at the query level—using rollups or continuous queries—than to fetch raw rows and paginate them in the browser.
Actionable checklist
- Audit the panels that time out most often and check whether their queries include an explicit
LIMIT. - Add
ORDER BYalongside everyLIMITto keep results deterministic. - Set
maxDataPointsin the panel JSON for provisioned dashboards so the limit cannot drift. - Verify the actual request parameters in the browser Network tab after saving.
- Re-test dashboards after Grafana upgrades or data source configuration changes.
The goal is not to fetch less data for its own sake, but to make the boundary between the data source and the browser explicit, testable, and consistent.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.