Skip to content

MySQL OpenTelemetry Dashboards

MySQL database monitoring dashboards using OpenTelemetry MySQL receiver metrics.

Overview

These dashboards provide comprehensive monitoring for MySQL database instances, including connections, buffer pool efficiency, query performance, and InnoDB metrics.

Dashboards

Dashboard File Description
Overview mysql-overview-esql.yaml Comprehensive MySQL metrics using ES|QL queries
Extended mysql-extended-esql.yaml Extended MySQL metrics for optional/disabled metrics

Both dashboards include navigation links for easy switching between views.

Dashboard Definitions

Overview (mysql-overview-esql.yaml)
---
# MySQL OpenTelemetry Overview Dashboard (ES|QL Version)
# Comprehensive MySQL metrics dashboard using OpenTelemetry MySQL receiver
# Uses ES|QL with TS command for time-series optimization
#
# Metrics reference: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/mysqlreceiver
dashboards:
  - id: mysql-otel-overview-esql
    name: '[Metrics MySQL] Overview'
    description: Comprehensive MySQL metrics dashboard using OpenTelemetry MySQL receiver (ES|QL version with TS command)
    controls:
      - type: options
        label: MySQL Host
        data_view: metrics-*
        field: resource.attributes.host.name
      - type: options
        label: MySQL Instance
        data_view: metrics-*
        field: resource.attributes.service.instance.id
    filters:
      - field: data_stream.dataset
        equals: mysqlreceiver.otel
    panels:
      # Navigation Links
      - title: Navigation Links
        size: {w: 48, h: 2}
        links:
          layout: horizontal
          items:
            - label: MySQL Overview
              dashboard: mysql-otel-overview-esql
            - label: MySQL Extended
              dashboard: mysql-otel-extended-esql

      # Overview Metrics Row (y=2, h=6)
      - title: Active Connections
        description: Connected client threads. Excludes aborted and disconnected threads.
        hide_title: true
        size: {w: 12, h: 4}
        esql:
          type: metric
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE attributes.kind == "connected"
            - STATS active_connections = MAX(mysql.threads)
          primary:
            field: active_connections
            label: Active Connections
            format:
              type: number
              decimals: 0
      - title: Buffer Pool Efficiency
        description: >-
          Clean pages / total pages. Higher = efficient memory use. Lower =
          more dirty pages requiring flush.
        hide_title: true
        size: {w: 12, h: 4}
        esql:
          type: metric
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.buffer_pool.usage IS NOT NULL
            - STATS clean_pages = MAX(mysql.buffer_pool.usage) BY attributes.status
            - STATS total = SUM(clean_pages), clean = SUM(CASE(attributes.status == "clean", clean_pages, 0))
            - EVAL efficiency = clean / total
          primary:
            field: efficiency
            label: Buffer Pool Efficiency
            format:
              type: percent
      - title: InnoDB Operations Rate
        hide_title: true
        size: {w: 12, h: 4}
        esql:
          type: metric
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.operations IS NOT NULL
            - STATS ops_rate = SUM(RATE(mysql.operations))
          primary:
            field: ops_rate
            label: InnoDB Ops/sec
      - title: Handler Operations Rate
        hide_title: true
        size: {w: 12, h: 4}
        esql:
          type: metric
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.handlers IS NOT NULL
            - STATS handler_rate = SUM(RATE(mysql.handlers))
          primary:
            field: handler_rate
            label: Handler Ops/sec

      # Buffer Pool Performance Section (y=8)
      - title: Buffer Pool Usage Over Time
        size: {w: 24, h: 9}
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.buffer_pool.usage IS NOT NULL
            - STATS usage = MAX(mysql.buffer_pool.usage) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), status = attributes.status
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: usage
              label: Buffer Pool Usage
              format:
                type: bytes
          breakdown:
            field: status
      - title: Buffer Pool Pages
        size: {w: 24, h: 9}
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.buffer_pool.pages IS NOT NULL
            - STATS pages = MAX(mysql.buffer_pool.pages) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), kind = attributes.kind
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: pages
              label: Buffer Pool Pages
          breakdown:
            field: kind
      - title: Buffer Pool Operations
        size: {w: 24, h: 9}
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.buffer_pool.operations IS NOT NULL
            - STATS ops_rate = SUM(RATE(mysql.buffer_pool.operations)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), operation =
              attributes.operation
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: ops_rate
              label: Operations/sec
          breakdown:
            field: operation
      - title: Buffer Pool Page Flushes
        size: {w: 24, h: 9}
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.buffer_pool.page_flushes IS NOT NULL
            - STATS flush_rate = SUM(RATE(mysql.buffer_pool.page_flushes)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend)
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: flush_rate
              label: Page Flushes/sec

      # InnoDB Operations Section (y=26)
      - title: Row Operations
        size: {w: 24, h: 9}
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.row_operations IS NOT NULL
            - STATS row_ops_rate = SUM(RATE(mysql.row_operations)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), operation = attributes.operation
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: row_ops_rate
              label: Row Ops/sec
          breakdown:
            field: operation
      - title: Page Operations
        size: {w: 24, h: 9}
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.page_operations IS NOT NULL
            - STATS page_ops_rate = SUM(RATE(mysql.page_operations)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), operation = attributes.operation
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: page_ops_rate
              label: Page Ops/sec
          breakdown:
            field: operation
      - title: InnoDB Operations (fsyncs, reads, writes)
        size: {w: 24, h: 9}
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.operations IS NOT NULL
            - STATS ops_rate = SUM(RATE(mysql.operations)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), operation = attributes.operation
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: ops_rate
              label: Operations/sec
          breakdown:
            field: operation
      - title: Double Writes
        size: {w: 24, h: 9}
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.double_writes IS NOT NULL
            - STATS double_writes_rate = SUM(RATE(mysql.double_writes)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), kind = attributes.kind
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: double_writes_rate
              label: Double Writes/sec
          breakdown:
            field: kind

      # Handler Operations Section (y=44)
      - title: Handler Operations
        size: {w: 48, h: 9}
        description: Handler operations rate by type
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.handlers IS NOT NULL
            - STATS handler_rate = SUM(RATE(mysql.handlers)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), kind = attributes.kind
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: handler_rate
              label: Handler Ops/sec
          breakdown:
            field: kind

      # Locks & Waits Section (y=53)
      - title: Lock Waits
        size: {w: 24, h: 9}
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.locks IS NOT NULL
            - STATS lock_rate = SUM(RATE(mysql.locks)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), kind = attributes.kind
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: lock_rate
              label: Locks/sec
          breakdown:
            field: kind
      - title: Row Lock Waits
        size: {w: 24, h: 9}
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.row_locks IS NOT NULL
            - STATS row_lock_rate = SUM(RATE(mysql.row_locks)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), kind = attributes.kind
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: row_lock_rate
              label: Row Locks/sec
          breakdown:
            field: kind

      # Log Operations Section (y=62)
      - title: Log Operations
        size: {w: 48, h: 9}
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.log_operations IS NOT NULL
            - STATS log_ops_rate = SUM(RATE(mysql.log_operations)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), operation = attributes.operation
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: log_ops_rate
              label: Log Ops/sec
          breakdown:
            field: operation

      # Table I/O Waits Section (y=71)
      - title: Table I/O Waits/sec by Table
        size: {w: 24, h: 9}
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.table.io.wait.count IS NOT NULL
            - STATS table_io_wait_rate = SUM(RATE(mysql.table.io.wait.count)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), table
              = attributes.table
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: table_io_wait_rate
              label: Table I/O Waits/sec
          breakdown:
            field: table
      - title: Index I/O Waits/sec by Index
        size: {w: 24, h: 9}
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.index.io.wait.count IS NOT NULL
            - STATS index_io_wait_rate = SUM(RATE(mysql.index.io.wait.count)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), index
              = attributes.index
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: index_io_wait_rate
              label: Index I/O Waits/sec
          breakdown:
            field: index

      # Resources Section (y=80)
      - title: Opened Resources
        size: {w: 24, h: 9}
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.opened_resources IS NOT NULL
            - STATS opened_rate = SUM(RATE(mysql.opened_resources)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), kind = attributes.kind
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: opened_rate
              label: Opened Resources/sec
          breakdown:
            field: kind
      - title: Temporary Resources
        size: {w: 24, h: 9}
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.tmp_resources IS NOT NULL
            - STATS tmp_rate = SUM(RATE(mysql.tmp_resources)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), resource = attributes.resource
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: tmp_rate
              label: Temp Resources/sec
          breakdown:
            field: resource

      # Threads & Sorts Section (y=89)
      - title: Thread Metrics
        size: {w: 24, h: 9}
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.threads IS NOT NULL
            - STATS thread_count = MAX(mysql.threads) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), kind = attributes.kind
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: thread_count
              label: Threads
              format:
                type: number
                decimals: 0
          breakdown:
            field: kind
      - title: Sort Operations
        size: {w: 24, h: 9}
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.sorts IS NOT NULL
            - STATS sorts_rate = SUM(RATE(mysql.sorts)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), kind = attributes.kind
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: sorts_rate
              label: Sorts/sec
          breakdown:
            field: kind

      # Uptime & Connection Stats (y=98)
      - title: MySQL Uptime
        size: {w: 24, h: 9}
        description: MySQL server uptime rate (should be 1 second/second when running)
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.uptime IS NOT NULL
            - STATS uptime_rate = SUM(RATE(mysql.uptime)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend)
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: uptime_rate
              label: Uptime Rate (sec/sec)
      - title: MySQLx Connections
        size: {w: 24, h: 9}
        esql:
          type: line
          query:
            - TS metrics-*
            - WHERE data_stream.dataset == "mysqlreceiver.otel"
            - WHERE mysql.mysqlx_connections IS NOT NULL
            - STATS mysqlx_conn_rate = SUM(RATE(mysql.mysqlx_connections)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), status =
              attributes.status
            - SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: mysqlx_conn_rate
              label: MySQLx Connections/sec
          breakdown:
            field: status
Extended (mysql-extended-esql.yaml)
---
# MySQL OpenTelemetry Extended Dashboard (ES|QL Version)
# Dashboard for optional MySQL metrics that require explicit configuration to enable
# Uses ES|QL with TS command for time-series optimization
#
# These metrics are disabled by default in the MySQL receiver. To enable them, update
# your OpenTelemetry Collector configuration for the MySQL receiver.
#
# Metrics reference: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/mysqlreceiver
dashboards:
  - id: mysql-otel-extended-esql
    name: '[Metrics MySQL] Extended'
    description: Extended MySQL metrics dashboard for optional metrics (connection, query, replication, table metrics)
    controls:
      - type: options
        label: MySQL Host
        data_view: metrics-*
        field: resource.attributes.host.name
      - type: options
        label: MySQL Instance
        data_view: metrics-*
        field: resource.attributes.service.instance.id
    filters:
      - field: data_stream.dataset
        equals: mysqlreceiver.otel
    panels:
      # Navigation Links
      - title: Navigation Links
        size: {w: 48, h: 2}
        links:
          layout: horizontal
          items:
            - label: MySQL Overview
              dashboard: mysql-otel-overview-esql
            - label: MySQL Extended
              dashboard: mysql-otel-extended-esql

      # Info Panel about Optional Metrics
      - size: {w: 48, h: 5}
        markdown:
          content: |
            ## Optional Metrics Dashboard
            This dashboard displays **optional metrics** that are disabled by default in the MySQL receiver.
            To enable these metrics, update your MySQL receiver configuration in the OpenTelemetry Collector.
            If panels show no data, the corresponding metric has not been enabled.

      # Connection Metrics Section (y=7)
      - title: Connection Count
        size: {w: 24, h: 9}
        description: Number of connections (mysql.connection.count)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.connection.count IS NOT NULL
            | STATS connection_count = MAX(mysql.connection.count) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend)
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: connection_count
              label: Connection Count
              format:
                type: number
                decimals: 0
      - title: Max Used Connections
        size: {w: 24, h: 9}
        description: Maximum number of connections used (mysql.max_used_connections)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.max_used_connections IS NOT NULL
            | STATS max_connections = MAX(mysql.max_used_connections) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend)
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: max_connections
              label: Max Used Connections
              format:
                type: number
                decimals: 0
      - title: Connection Errors
        size: {w: 48, h: 9}
        description: Connection errors by type (mysql.connection.errors)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.connection.errors IS NOT NULL
            | STATS error_count = MAX(mysql.connection.errors) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), error = attributes.error
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: error_count
              label: Errors
              format:
                type: number
                decimals: 0
          breakdown:
            field: error

      # Query Metrics Section (y=25)
      - title: Query Count
        size: {w: 24, h: 9}
        description: Total query count rate (mysql.query.count)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.query.count IS NOT NULL
            | STATS query_rate = SUM(RATE(mysql.query.count)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend)
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: query_rate
              label: Queries/sec
      - title: Slow Query Count
        size: {w: 24, h: 9}
        description: Slow query rate (mysql.query.slow.count)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.query.slow.count IS NOT NULL
            | STATS slow_query_rate = SUM(RATE(mysql.query.slow.count)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend)
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: slow_query_rate
              label: Slow Queries/sec
      - title: Client Query Count
        size: {w: 48, h: 9}
        description: Client query count rate (mysql.query.client.count)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.query.client.count IS NOT NULL
            | STATS client_query_rate = SUM(RATE(mysql.query.client.count)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend)
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: client_query_rate
              label: Client Queries/sec

      # Command Metrics Section (y=43)
      - title: Commands by Type
        size: {w: 48, h: 9}
        description: Command execution rate by type (mysql.commands)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.commands IS NOT NULL
            | STATS command_rate = SUM(RATE(mysql.commands)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), command = attributes.command
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: command_rate
              label: Commands/sec
          breakdown:
            field: command

      # Replication Metrics Section (y=52)
      - title: Replica Time Behind Source
        size: {w: 24, h: 9}
        description: Replication lag in seconds (mysql.replica.time_behind_source)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.replica.time_behind_source IS NOT NULL
            | STATS lag_seconds = MAX(mysql.replica.time_behind_source) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend)
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: lag_seconds
              label: Seconds Behind Source
      - title: Replica SQL Delay
        size: {w: 24, h: 9}
        description: Configured replication delay (mysql.replica.sql_delay)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.replica.sql_delay IS NOT NULL
            | STATS sql_delay = MAX(mysql.replica.sql_delay) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend)
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: sql_delay
              label: SQL Delay (seconds)

      # Table Metrics Section (y=61)
      - title: Table Rows by Table
        size: {w: 24, h: 9}
        description: Row count per table (mysql.table.rows)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.table.rows IS NOT NULL
            | STATS row_count = MAX(mysql.table.rows) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), table = attributes.table
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: row_count
              label: Rows
              format:
                type: number
                decimals: 0
          breakdown:
            field: table
      - title: Table Size by Table
        size: {w: 24, h: 9}
        description: Table size in bytes by table (mysql.table.size)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.table.size IS NOT NULL
            | STATS size_bytes = MAX(mysql.table.size) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), table = attributes.table
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: size_bytes
              label: Size
              format:
                type: bytes
          breakdown:
            field: table
      - title: Table Average Row Length
        size: {w: 48, h: 9}
        description: Average row length per table (mysql.table.average_row_length)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.table.average_row_length IS NOT NULL
            | STATS avg_row_length = MAX(mysql.table.average_row_length) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), table = attributes.table
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: avg_row_length
              label: Avg Row Length
              format:
                type: bytes
          breakdown:
            field: table

      # Additional Optional Metrics (y=79)
      - title: Client Network I/O
        size: {w: 24, h: 9}
        description: Network bytes sent/received (mysql.client.network.io)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.client.network.io IS NOT NULL
            | STATS io_bytes = SUM(RATE(mysql.client.network.io)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), kind = attributes.kind
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: io_bytes
              label: Bytes/sec
              format:
                type: bytes
          breakdown:
            field: kind
      - title: Joins by Type
        size: {w: 24, h: 9}
        description: Join operations by type (mysql.joins)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.joins IS NOT NULL
            | STATS joins_rate = SUM(RATE(mysql.joins)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), kind = attributes.kind
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: joins_rate
              label: Joins/sec
          breakdown:
            field: kind

      # Table Lock Metrics (y=88)
      - title: Table Lock Wait Read
        size: {w: 24, h: 9}
        description: Table read lock wait count (mysql.table.lock_wait.read.count)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.table.lock_wait.read.count IS NOT NULL
            | STATS lock_count = SUM(RATE(mysql.table.lock_wait.read.count)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), kind = attributes.kind
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: lock_count
              label: Read Lock Waits/sec
          breakdown:
            field: kind
      - title: Table Lock Wait Write
        size: {w: 24, h: 9}
        description: Table write lock wait count (mysql.table.lock_wait.write.count)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.table.lock_wait.write.count IS NOT NULL
            | STATS lock_count = SUM(RATE(mysql.table.lock_wait.write.count)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), kind = attributes.kind
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: lock_count
              label: Write Lock Waits/sec
          breakdown:
            field: kind

      # Table Open Cache and Prepared Statements (y=97)
      - title: Table Open Cache
        size: {w: 24, h: 9}
        description: Table open cache hits/misses (mysql.table_open_cache)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.table_open_cache IS NOT NULL
            | STATS cache_count = SUM(RATE(mysql.table_open_cache)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), status = attributes.status
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: cache_count
              label: Operations/sec
          breakdown:
            field: status
      - title: Prepared Statements
        size: {w: 24, h: 9}
        description: Prepared statement operations (mysql.prepared_statements)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.prepared_statements IS NOT NULL
            | STATS stmt_count = SUM(RATE(mysql.prepared_statements)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), command = attributes.command
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: stmt_count
              label: Statements/sec
          breakdown:
            field: command

      # Statement Events (y=106)
      - title: Statement Events by Schema
        size: {w: 48, h: 9}
        description: Statement event count by schema (mysql.statement_event.count)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.statement_event.count IS NOT NULL
            | STATS event_count = SUM(RATE(mysql.statement_event.count)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), schema = attributes.schema
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: event_count
              label: Events/sec
          breakdown:
            field: schema

      # MySQLx Worker Threads (y=115)
      - title: MySQLx Worker Threads
        size: {w: 48, h: 9}
        description: MySQLx worker threads by status (mysql.mysqlx_worker_threads)
        esql:
          type: line
          query: |
            TS metrics-*
            | WHERE data_stream.dataset == "mysqlreceiver.otel"
            | WHERE mysql.mysqlx_worker_threads IS NOT NULL
            | STATS thread_count = MAX(mysql.mysqlx_worker_threads) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), kind = attributes.kind
            | SORT time_bucket ASC
          dimension:
            field: time_bucket
            label: Time
            data_type: date
          metrics:
            - field: thread_count
              label: Threads
              format:
                type: number
                decimals: 0
          breakdown:
            field: kind

Prerequisites

  • MySQL: MySQL 5.7+ or 8.x database server
  • OpenTelemetry Collector: Collector Contrib with MySQL receiver configured
  • Kibana: Version 9.2 or later (dashboards use ES|QL TS command)

Data Requirements

  • Data stream dataset: mysqlreceiver.otel
  • Data view: metrics-*

OpenTelemetry Collector Configuration

receivers:
  mysql:
    endpoint: localhost:3306
    username: ${env:MYSQL_USERNAME}
    password: ${env:MYSQL_PASSWORD}
    collection_interval: 10s

exporters:
  elasticsearch:
    endpoints: ["https://your-elasticsearch-instance:9200"]

service:
  pipelines:
    metrics:
      receivers: [mysql]
      exporters: [elasticsearch]

Metrics Reference

Default Metrics

Metric Type Unit Description Attributes
mysql.buffer_pool.data_pages Sum 1 Number of data pages in the InnoDB buffer pool status
mysql.buffer_pool.limit Sum By Configured size of the InnoDB buffer pool
mysql.buffer_pool.operations Sum 1 Number of operations on the InnoDB buffer pool operation
mysql.buffer_pool.page_flushes Sum 1 Number of requests to flush pages from buffer pool
mysql.buffer_pool.pages Sum 1 Number of pages in the InnoDB buffer pool kind
mysql.buffer_pool.usage Sum By Bytes in the InnoDB buffer pool status
mysql.double_writes Sum 1 Writes to the InnoDB doublewrite buffer kind
mysql.handlers Sum 1 Requests to various MySQL handlers kind
mysql.index.io.wait.count Sum 1 Total I/O wait count for an index operation, table, schema, index
mysql.index.io.wait.time Sum ns Total I/O wait time for an index operation, table, schema, index
mysql.locks Sum 1 Number of MySQL locks kind
mysql.log_operations Sum 1 Number of InnoDB log operations operation
mysql.mysqlx_connections Sum 1 Document Store connections status
mysql.opened_resources Sum 1 Number of opened resources kind
mysql.operations Sum 1 Number of InnoDB operations operation
mysql.page_operations Sum 1 Number of InnoDB page operations operation
mysql.prepared_statements Sum 1 Prepared statement commands issued command
mysql.row_locks Sum 1 Number of InnoDB row locks kind
mysql.row_operations Sum 1 Number of InnoDB row operations operation
mysql.sorts Sum 1 Number of MySQL sorts kind
mysql.table.io.wait.count Sum 1 Total I/O wait count for a table operation, table, schema
mysql.table.io.wait.time Sum ns Total I/O wait time for a table operation, table, schema
mysql.threads Sum 1 State of MySQL threads kind
mysql.tmp_resources Sum 1 Number of created temporary resources resource
mysql.uptime Sum s Seconds the server has been up

Optional Metrics (disabled by default)

Metric Type Unit Description Attributes
mysql.client.network.io Sum By Bytes transmitted between server and clients kind
mysql.commands Sum 1 Number of times each command has been executed command
mysql.connection.count Sum 1 Connection attempts to the MySQL server
mysql.connection.errors Sum 1 Errors during client connection process error
mysql.joins Sum 1 Joins that perform table scans kind
mysql.max_used_connections Sum 1 Maximum connections used since server started
mysql.mysqlx_worker_threads Sum 1 MySQLx worker thread count kind
mysql.query.client.count Sum 1 Number of client statements executed
mysql.query.count Sum 1 Number of queries executed
mysql.query.slow.count Sum 1 Number of slow queries
mysql.replica.sql_delay Sum s Configured replication delay in seconds
mysql.replica.time_behind_source Sum s Replication lag in seconds
mysql.statement_event.count Sum 1 Statement event count by schema schema, digest, digest_text, kind
mysql.table.average_row_length Sum By Average row length per table table, schema
mysql.table.lock_wait.read.count Sum 1 Table read lock wait count schema, table, kind
mysql.table.lock_wait.write.count Sum 1 Table write lock wait count schema, table, kind
mysql.table.rows Sum 1 Number of rows for a given table table, schema
mysql.table.size Sum By Table size in bytes table, schema, kind
mysql.table_open_cache Sum 1 Table open cache operations status

Metric Attributes

Attribute Values Description
status dirty, clean Buffer pool status
kind (pages) data, free, misc, total Page type
kind (handlers) commit, delete, update, write, read_first, read_key, read_next, read_prev, read_rnd, read_rnd_next Handler type
kind (locks) immediate, waited Lock type
kind (double_writes) pages_written, writes Double write type
kind (row_locks) waits, time Row lock type
kind (sorts) merge_passes, range, rows, scan Sort type
kind (threads) cached, connected, created, running Thread state
operation (log) waits, write_requests, writes, fsyncs Log operation type
operation (InnoDB) fsyncs, reads, writes InnoDB operation type
operation (page) created, read, written Page operation type
operation (row) deleted, inserted, read, updated Row operation type
resource disk_tables, files, tables Temporary resource type
kind (mysqlx_threads) available, active MySQLx worker thread state
kind (read_lock) normal, with_shared_locks, high_priority, no_insert, external Read lock type
kind (write_lock) allow_write, concurrent_insert, low_priority, normal, external Write lock type
kind (table_size) data, index Table size type
kind (joins) full, full_range, range, range_check, scan Join type
kind (event_state) errors, warnings, rows_affected, rows_sent, rows_examined, created_tmp_disk_tables, created_tmp_tables, sort_merge_passes, sort_rows, no_index_used Statement event state
status (cache) hit, miss, overflow Cache access status
status (connection) accepted, closed, rejected Connection status
error accept, internal, max_connections, peer_address, select, tcpwrap, aborted, aborted_clients, locked Connection error type
command delete, delete_multi, insert, select, update, update_multi Command type
command (prepared) execute, close, fetch, prepare, reset, send_long_data Prepared statement command

Resource Attributes

Attribute Description
host.name MySQL host name
service.instance.id MySQL instance identifier

Metrics Not Used in Dashboards

The following default metrics are available from the MySQL receiver but are not currently visualized in the dashboards:

Metric Type Unit Description Attributes
mysql.buffer_pool.data_pages Sum 1 Number of data pages in the InnoDB buffer pool status
mysql.buffer_pool.limit Sum By Configured size of the InnoDB buffer pool
mysql.index.io.wait.time Sum ns Total I/O wait time for an index operation, table, schema, index
mysql.table.io.wait.time Sum ns Total I/O wait time for a table operation, table, schema

All optional metrics listed above are used in the Extended dashboard.