---
title: TIMEOUT_EXCEEDED ClickHouse error
meta:
  description: Learn how to fix the TIMEOUT_EXCEEDED error in ClickHouse and Tinybird. Understand what causes it and see examples of how to resolve it
---

# TIMEOUT_EXCEEDED ClickHouse error

{% callout %}
This error occurs when a query takes longer than the configured timeout limit. It's common with complex queries or large datasets that exceed performance thresholds.
{% /callout %}

The `TIMEOUT_EXCEEDED` error in ClickHouse (and Tinybird) happens when a query execution time exceeds the configured timeout limit. This typically occurs with complex queries, large datasets, or operations that require more time than allowed by the system configuration.

## What causes this error

You'll typically see it when:

* Complex queries with multiple JOINs or subqueries
* Large datasets that exceed memory or processing limits
* Queries with insufficient indexes or optimization
* System resource constraints (CPU, memory, I/O)
* Network latency issues in distributed queries
* Queries that trigger complex aggregations or transformations

{% callout type="tip" %}
Timeout errors often indicate that your query needs optimization rather than just increasing the timeout limit.
{% /callout %}

## Example errors

```sql {% title="Fails: complex query with multiple JOINs" %}
SELECT
    u.id,
    u.name,
    COUNT(e.id) as event_count,
    AVG(e.value) as avg_value
FROM users u
JOIN events e ON u.id = e.user_id
JOIN sessions s ON u.id = s.user_id
JOIN metrics m ON s.id = m.session_id
WHERE e.timestamp >= '2024-01-01'
GROUP BY u.id, u.name
HAVING event_count > 100
ORDER BY avg_value DESC
```

```sql {% title="Fails: large dataset without proper filtering" %}
SELECT * FROM events
WHERE timestamp >= '2020-01-01'
ORDER BY timestamp DESC
```

```sql {% title="Fails: complex aggregation without optimization" %}
SELECT
    user_id,
    COUNT(*) as total_events,
    COUNT(DISTINCT event_type) as unique_events,
    AVG(value) as avg_value,
    STDDEV(value) as std_value
FROM events
GROUP BY user_id
HAVING total_events > 1000
```

## How to fix it

### Optimize query structure

Break down complex queries into simpler parts:

```sql {% title="Fix: simplified query" %}
-- First, get the user list
WITH user_events AS (
    SELECT user_id, COUNT(*) as event_count
    FROM events
    WHERE timestamp >= '2024-01-01'
    GROUP BY user_id
    HAVING event_count > 100
)
-- Then, get detailed information
SELECT
    u.id,
    u.name,
    ue.event_count
FROM users u
JOIN user_events ue ON u.id = ue.user_id
ORDER BY ue.event_count DESC
```

### Add proper filtering

Use WHERE clauses to limit data early:

```sql {% title="Fix: add time filtering" %}
SELECT * FROM events
WHERE timestamp >= '2024-01-01'
  AND timestamp < '2024-02-01'
ORDER BY timestamp DESC
```

### Use appropriate indexes

Ensure your tables have proper indexes:

```sql {% title="Create optimized table" %}
CREATE TABLE events (
    id UInt64,
    user_id UInt64,
    event_type String,
    timestamp DateTime,
    value Float64
) ENGINE = MergeTree()
ORDER BY (timestamp, user_id)
PARTITION BY toYYYYMM(timestamp)
```

### Limit result sets

Use LIMIT clauses to prevent large results:

```sql {% title="Fix: add LIMIT clause" %}
SELECT user_id, event_type, timestamp
FROM events
WHERE timestamp >= '2024-01-01'
ORDER BY timestamp DESC
LIMIT 1000
```

## Common patterns and solutions

### Complex JOIN optimization

Break down complex JOINs:

```sql {% title="Optimized JOIN approach" %}
-- Step 1: Get filtered base data
WITH base_events AS (
    SELECT user_id, event_type, timestamp
    FROM events
    WHERE timestamp >= '2024-01-01'
)
-- Step 2: Join with user data
SELECT
    u.id,
    u.name,
    be.event_type,
    be.timestamp
FROM users u
JOIN base_events be ON u.id = be.user_id
LIMIT 1000
```

### Aggregation optimization

Optimize aggregations with pre-filtering:

```sql {% title="Optimized aggregation" %}
SELECT
    user_id,
    COUNT(*) as total_events,
    COUNT(DISTINCT event_type) as unique_events
FROM events
WHERE timestamp >= '2024-01-01'
  AND user_id IN (
    SELECT DISTINCT user_id
    FROM events
    WHERE timestamp >= '2024-01-01'
    GROUP BY user_id
    HAVING COUNT(*) > 100
  )
GROUP BY user_id
```

### Subquery optimization

Replace complex subqueries with CTEs:

```sql {% title="Using CTEs instead of subqueries" %}
WITH user_stats AS (
    SELECT user_id, COUNT(*) as event_count
    FROM events
    WHERE timestamp >= '2024-01-01'
    GROUP BY user_id
),
top_users AS (
    SELECT user_id
    FROM user_stats
    WHERE event_count > 100
)
SELECT
    u.id,
    u.name,
    us.event_count
FROM users u
JOIN user_stats us ON u.id = us.user_id
JOIN top_users tu ON u.id = tu.user_id
```

## Tinybird-specific notes

In Tinybird, timeout errors often occur when:

* Creating complex Materialized Views
* Processing large amounts of data in Pipes
* Running queries against very large datasets
* Using complex transformations in API endpoints

To debug in Tinybird:

1. Use the Query Builder to test query performance
2. Check the query execution plan
3. Monitor resource usage in the UI
4. Consider breaking complex operations into smaller Pipes

{% callout type="tip" %}
Use Tinybird's query profiling to identify bottlenecks before they cause timeouts.
{% /callout %}

## Best practices

### Query design

* Start with simple queries and add complexity gradually
* Use appropriate WHERE clauses to filter data early
* Avoid SELECT * on large tables
* Use LIMIT clauses for exploratory queries

### Performance optimization

* Create proper indexes on frequently queried columns
* Use partitioning for time-series data
* Consider materialized views for complex aggregations
* Monitor query execution plans

### Resource management

* Set appropriate timeout limits for different query types
* Monitor system resource usage
* Use connection pooling for multiple queries
* Implement retry logic with exponential backoff

## Configuration options

### Adjusting timeout settings

```sql {% title="Check current timeout settings" %}
SELECT name, value
FROM system.settings
WHERE name LIKE '%timeout%'
```

### Setting query timeout

```sql {% title="Set query timeout" %}
SET max_execution_time = 300; -- 5 minutes
```

## See also

* [Query Optimization](/work-with-data/optimization)
* [Performance Tuning](/forward/work-with-data/optimize)
* [Common performance issues](/sql-reference/performance)
* [Working with large datasets](/forward/work-with-data/optimize)
