Grafana SQL Queries

Many businesses keep their most valuable numbers in relational databases: orders, sign-ups, payments, and stock levels. Grafana connects to MySQL, PostgreSQL, and Microsoft SQL Server, so you can chart those numbers beside your server metrics. A basic knowledge of SELECT statements is enough to begin.

The Translator Analogy

A database speaks in rows and columns. Grafana panels speak in time and values. A SQL query acts as the translator between the two languages. You write a query that returns the right columns, and Grafana turns the answer into a line, a bar, or a table.

Database table                      Grafana panel
+---------------------+-------+
| created_at          | total |          orders
+---------------------+-------+     40 |      /\
| 2026-03-01 10:00    |  12   |  ---> 20 |  /\_/  \
| 2026-03-01 11:00    |  31   |      0 +---------------
| 2026-03-01 12:00    |  27   |         10h  11h  12h
+---------------------+-------+

Connect a Database

  1. Open Connections and choose Add new connection.
  2. Search for MySQL or PostgreSQL and select it.
  3. Enter the host with port, the database name, the user, and the password.
  4. Click Save and test and wait for the green success message.

Create a dedicated database user with read-only rights for Grafana. A read-only user protects your data from accidental changes, and it limits the damage if the credentials ever leak.

Builder and Code Modes

The query editor offers two modes. Builder mode lets you pick a table, columns, and filters from drop-down menus. Code mode gives you a plain text box for full SQL. Beginners start with Builder and switch to Code when they need joins or custom logic. Grafana keeps the generated SQL visible, which teaches you the syntax as you work.

Time Series Format

For a line chart, set the query format to Time series. Grafana expects two things.

  • A column named time that holds a date and time.
  • One or more numeric columns that hold the values.
SELECT
  created_at AS time,
  total_amount AS revenue
FROM orders
WHERE $__timeFilter(created_at)
ORDER BY created_at

The macro $__timeFilter(created_at) adds a WHERE condition that matches the dashboard time range. Zoom the chart and the query follows automatically.

Useful Macros

MacroWhat It Does
$__timeFilter(column)Limits rows to the selected time range
$__timeGroup(column, '1h')Groups rows into hourly buckets
$__timeFrom()Returns the start of the time range
$__timeTo()Returns the end of the time range
$__unixEpochFilter(column)Filters a column that stores Unix timestamps

Group Data Into Buckets

Raw rows rarely make a good chart. Thousands of orders look like noise. Grouping them into hourly totals reveals the pattern.

SELECT
  $__timeGroup(created_at, '1h') AS time,
  COUNT(*) AS orders
FROM orders
WHERE $__timeFilter(created_at)
GROUP BY 1
ORDER BY 1

The query counts orders in every hour of the range. Grafana draws a clear line that shows busy and quiet periods.

Split One Query Into Several Lines

Add a text column named metric and Grafana draws one line for each distinct value.

SELECT
  $__timeGroup(created_at, '1h') AS time,
  country AS metric,
  SUM(total_amount) AS revenue
FROM orders
WHERE $__timeFilter(created_at)
GROUP BY 1, 2
ORDER BY 1
Revenue by country
  |   India  ____/\___
  |   USA   __/    \___
  |   UK    ___________
  +-----------------------

Table Format

Set the format to Table when you want a list in place of a chart. A table does not need a time column. Use it for top ten lists, recent orders, or current stock.

SELECT product_name, SUM(quantity) AS sold
FROM order_items
GROUP BY product_name
ORDER BY sold DESC
LIMIT 10

Use Variables in SQL

Dashboard variables work inside queries. Write the variable name with a dollar sign and Grafana swaps in the selected value.

SELECT $__timeGroup(created_at, '1h') AS time,
       SUM(total_amount) AS revenue
FROM orders
WHERE $__timeFilter(created_at)
  AND country = '$country'
GROUP BY 1
ORDER BY 1

A drop-down named country now filters the chart. For multi-select variables, write IN ($country) and Grafana builds the list for you.

Keep Queries Fast

  • Index the time column your queries filter on.
  • Select only the columns you need.
  • Group data into buckets before it reaches the panel.
  • Test slow queries directly in the database to find the cause.