dbtrail

Forensics

API endpoints for forensic investigation — capabilities, enrichment, queries, and row tracing

The forensics API provides endpoints for investigating who made database changes, what connections were active, and what SQL was executed. Requires the forensics plan feature (Pro, Premium, or Enterprise).

Endpoints

MethodEndpointPermissionDescription
GET/forensics/capabilities/{server_id}forensics plan featureCheck available forensic data sources
POST/forensics/enrichforensics plan featureLook up connection metadata for thread IDs
POST/forensics/queryforensics plan featureQuery user activity, connections, or DDL history
POST/forensics/who-changedforensics plan featureTrace who modified a specific row

Check capabilities

GET /forensics/capabilities/{server_id}

Detect available forensic data sources on a MySQL server. Call this first to understand what data is available before running other forensic queries.

Response

{
  "success": true,
  "performance_schema": {
    "enabled": true,
    "consumers": {
      "events_statements_history": true,
      "events_statements_history_long": false
    },
    "threads_accessible": true
  },
  "audit_log": {
    "installed": true,
    "plugin_name": "audit_log",
    "plugin_status": "ACTIVE",
    "variant": "percona",
    "config": {
      "audit_log_format": "JSON",
      "audit_log_file": "/var/log/mysql/audit.log"
    }
  },
  "server_info": {
    "version": "8.0.35",
    "version_comment": "Percona Server",
    "variant": "percona"
  },
  "setup_guide": {
    "summary": "Enable events_statements_history_long for full statement history",
    "recommendations": [
      {
        "category": "performance_schema",
        "title": "Enable long statement history",
        "description": "The events_statements_history_long consumer is disabled",
        "impact": "Enables forensic queries across all threads, not just active ones",
        "performance_note": "Minimal overhead on most workloads",
        "runtime_sql": [
          "UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'events_statements_history_long'"
        ],
        "mycnf_snippet": "",
        "priority": "high"
      }
    ]
  }
}

When all forensic capabilities are already optimal, setup_guide may be null.


Enrich thread IDs

POST /forensics/enrich

Look up connection metadata for specific MySQL thread/connection IDs. Queries performance_schema.threads and session_connect_attrs to resolve thread IDs to user@host, client program, and connection attributes.

Request body

{
  "server_id": "uuid",
  "thread_ids": [8834, 8835]
}
FieldRequiredDescription
server_idyesServer UUID
thread_idsyesArray of MySQL thread/connection IDs to look up (1–500 items)

Response

{
  "success": true,
  "threads": {
    "8834": {
      "user": "app_user",
      "host": "10.0.1.50",
      "connection_id": 8834,
      "db": "mydb",
      "command": "Query",
      "state": "executing",
      "connection_attributes": {
        "_client_name": "libmysql",
        "program_name": "myapp-backend",
        "_os": "Linux",
        "_pid": "12345"
      }
    }
  },
  "source": "performance_schema",
  "not_found": [8835],
  "fallback_queries": [
    {
      "description": "Look up thread 8835 in processlist",
      "sql": "SELECT * FROM information_schema.PROCESSLIST WHERE ID = 8835"
    }
  ]
}

Thread IDs no longer present in performance_schema appear in not_found with corresponding fallback_queries.


Forensic queries

POST /forensics/query

Execute a forensic query against the MySQL server. The query_type field determines what data is returned.

Request body

{
  "server_id": "uuid",
  "query_type": "user_activity",
  "user": "app_user",
  "limit": 50
}
FieldRequiredDescription
server_idyesServer UUID
query_typeyesOne of user_activity, connection_history, ddl_history
userdependsMySQL username (required for user_activity; at least user or host required for connection_history)
hostnoFilter by client host/IP
schemanoFilter DDL history by schema
since / untilnoTime range (ISO 8601)
limitnoMax results (1–1000, default: 50)

Query types

TypeRequired fieldsDescription
user_activityuserRecent SQL statements by a MySQL user
connection_historyuser or hostActive connections matching filter
ddl_history(optional: schema)Recent DDL statements (CREATE/ALTER/DROP)

Response

Results for user_activity and ddl_history are returned in the events array. Results for connection_history are returned in the connections array.

{
  "success": true,
  "events": [
    {
      "connection_id": 8834,
      "user": "app_user",
      "host": "10.0.1.50",
      "sql_text": "UPDATE orders SET status = 'shipped' WHERE id = 42",
      "rows_affected": 1,
      "duration_ms": 2.4,
      "current_db": "mydb"
    }
  ],
  "connections": [],
  "source": "performance_schema",
  "count": 1
}

When performance_schema is unavailable, see Fallback behavior below.


Who changed a row

POST /forensics/who-changed

Trace who modified a specific row. Queries binlog events for the given table and primary key, then correlates with performance_schema data to identify the MySQL user, host, and client program responsible for each change.

Request body

{
  "server_id": "uuid",
  "schema": "mydb",
  "table": "orders",
  "pk": "42",
  "since": "2026-03-01T00:00:00Z"
}
FieldRequiredDescription
server_idyesServer UUID
schemayesDatabase schema name
tableyesTable name
pkyesPrimary key value
sincenoOnly show changes after this time (ISO 8601)
untilnoOnly show changes before this time (ISO 8601)
limitnoMax results (1–1000, default: 50)

Response

{
  "success": true,
  "events": [
    {
      "event_id": "12345",
      "timestamp": "2026-03-15 09:22:31",
      "event_type": "UPDATE",
      "schema": "mydb",
      "table": "orders",
      "primary_key": {"id": 42},
      "forensics": {
        "user": "app_user@10.0.1.50",
        "host": "10.0.1.50",
        "client_program": "myapp-backend",
        "connection_id": 8834
      }
    }
  ],
  "total_count": 1,
  "forensic_source": "performance_schema"
}

When forensic enrichment isn't possible for historical connections no longer in performance_schema, events include forensic_queries with fallback SQL instead of the forensics object.


Fallback behavior

When performance_schema is unavailable or the relevant consumers are disabled, forensic endpoints return "source": "fallback" with ready-to-run SQL queries that can be executed directly against MySQL:

{
  "success": true,
  "events": [],
  "source": "fallback",
  "fallback_queries": [
    {
      "description": "Check current connections for this user",
      "sql": "SELECT * FROM information_schema.PROCESSLIST WHERE USER = 'app_user'"
    },
    {
      "description": "Recent statement history (requires events_statements_history consumer)",
      "sql": "SELECT t.PROCESSLIST_ID, t.PROCESSLIST_HOST, esh.SQL_TEXT ..."
    }
  ],
  "note": "performance_schema.events_statements_history_long is not available. Use the provided SQL queries to investigate."
}

On this page