> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://docs.ampdb.io/api/mcp` to find what you need.

# Query Server

The query server answers SQL queries over the datasets Amp has extracted. It serves them over
[Arrow Flight](/querying/arrow-flight), a gRPC protocol that sends results in Arrow's columnar format, on port `1602`.
It runs both kinds of queries:

* **[Batch queries](/querying/batch-queries)** return their results once, like most databases.
* **[Streaming queries](/querying/streaming-queries)** keep returning new rows as Amp extracts new blocks, until the
  client stops reading.

It reads which files each table has from the [metadata database](/running-amp/metadata-database), and their data from
[storage](/running-amp/storage). It doesn't write datasets' files or their file lists, so you can run as many query
servers as your queries need.

Solo mode runs a query server in its process. In [distributed mode](/running-amp/distributed-mode), you run it with
`ampd server`.

## Prerequisites

* A [configuration file](/running-amp/configuration) with the metadata database's URL and your storage locations.
* A migrated metadata database, unless the configuration lets the query server migrate it
  ([`auto_migrate`](/running-amp/metadata-database#auto_migrate)).

## Start the query server

:::terminal
```bash
ampd --config config.toml server
```

```
2026-10-30T16:51:20.814188Z  INFO connect_pool_with_config: amp_metadb: Verifying metadata database migration state (auto_migrate = false)...
2026-10-30T16:51:20.821694Z  INFO connect_pool_with_config: amp_metadb: Metadata database migration state verified
2026-10-30T16:51:20.836377Z  INFO ampd::server_cmd: Memory limit is unlimited
2026-10-30T16:51:20.836415Z  INFO ampd::server_cmd: Spill to disk allowed: false
2026-10-30T16:51:20.844336Z  INFO ampd::server_cmd: Arrow Flight SQL server running at 0.0.0.0:1602
```
:::

`Memory limit` is [`max_mem_mb`](/running-amp/query-server#memory), and `Spill to disk allowed` says whether
[`spill_location`](/running-amp/query-server#memory) is set.

To query it, use [`ampsql`](/clis/ampsql), which connects to `http://localhost:1602` by default, an
[SDK](/sdks/typescript), or any Arrow Flight client: see [Arrow Flight](/querying/arrow-flight).

## Settings

The query server reads the [shared settings](/running-amp/configuration#per-service-settings) and the `[server]`
section. Each `[server]` setting except `flight_addr`, `keep_alive_interval`, and `query_timeout_secs` can also be set
once at the top level, for the query server and workers both: see
[Global defaults](/running-amp/configuration#global-defaults).

| Setting                                                                                               | Default        | Description                                                                                                           |
| ----------------------------------------------------------------------------------------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------- |
| [`flight_addr`](/running-amp/configuration-reference#serverflight_addr)                               | `0.0.0.0:1602` | The address Arrow Flight and `/healthz` listen on.                                                                    |
| [`max_mem_mb`](/running-amp/configuration-reference#servermax_mem_mb)                                 | `0`            | The memory all queries share, in MiB. `0` is unlimited. See [Memory](/running-amp/query-server#memory).                                        |
| [`query_max_mem_mb`](/running-amp/configuration-reference#serverquery_max_mem_mb)                     | `0`            | The memory each batch query, or each step of a streaming query, may use, in MiB. `0` is unlimited.                    |
| [`spill_location`](/running-amp/configuration-reference#serverspill_location)                         | `[]`           | Directories where queries write temporary files when they run out of memory. Empty, they fail instead.                |
| [`query_timeout_secs`](/running-amp/configuration-reference#serverquery_timeout_secs)                 | `0`            | How long a batch query may run, in seconds. `0` is unlimited. See [Timeouts](/running-amp/query-server#timeouts).                              |
| [`keep_alive_interval`](/running-amp/configuration-reference#serverkeep_alive_interval)               | `30`           | How often, in seconds, a streaming query sends a message to keep its connection alive, from its start. At least `30`. |
| [`microbatch_max_interval`](/running-amp/configuration-reference#servermicrobatch_max_interval)       | `100000`       | The most blocks a streaming query processes at once, unless the query sets its own.                                   |
| [`metadata_fetch_concurrency`](/running-amp/configuration-reference#servermetadata_fetch_concurrency) | `32`           | How many requests for Parquet metadata a query sends the metadata database at once, per table.                        |
| [`[server.metadb]`](/running-amp/metadata-database#per-service-pools)                                 |                | The query server's own connection pool settings.                                                                      |

The [metadata caches](/running-amp/storage/metadata-caching), which save the query server trips to the metadata database
while it plans queries, are set in the shared `[writer]` and `[location_membership]` sections.

### Memory

Amp runs queries with a memory budget, in MiB (1,048,576 bytes), at two levels:

* **`max_mem_mb`** caps the memory every query running on this query server uses together.
* **`query_max_mem_mb`** caps each batch query, and each step of a streaming query. A streaming query processes new
  blocks in steps, called microbatches; with this limit set, Amp sizes each one to stay within it.

A query that needs more memory than it's allowed fails with the gRPC status `resource_exhausted`, unless it can write
its intermediate data to disk: set `spill_location` to one or more directories with free space for that.

```toml [config.toml]
[server]
max_mem_mb = 16384      # 16 GiB for all queries
query_max_mem_mb = 2048 # 2 GiB for each one
spill_location = ["/var/tmp/amp-spill"]
```

These limits cover what queries reserve to run, not every byte the process uses: leave room for the rest, like the
metadata caches. To give each user a budget, see [Limits](/querying/limits).

### Timeouts (Experimental)

`query_timeout_secs` stops a batch query that runs longer than it, and fails it with the gRPC status
`deadline_exceeded`. It doesn't apply to streaming queries, which run for as long as their client reads them.

```toml [config.toml]
[server]
query_timeout_secs = 300
```

### Streaming

* **`keep_alive_interval`**: the query server sends a small message at this interval, counted from the start of a
  streaming query, whether it has new rows or not, so proxies and load balancers don't close an idle connection. Values
  below `30` count as `30`.
* **`microbatch_max_interval`**: the default largest step of a streaming query, in blocks. A query can set its own
  with `SETTINGS microbatch_max_interval = 5000`. See [Streaming Queries](/querying/streaming-queries).

## Health check

The query server answers `GET /healthz` over HTTP on its Arrow Flight port, with `200 OK` once it listens:

```bash
curl -i http://localhost:1602/healthz
```

## Scaling and security

Run several query servers behind a load balancer that supports gRPC, HTTP/2, and long-lived connections, since
streaming queries stay open. The query server doesn't authenticate clients or encrypt connections: expose it through a
gateway that does. See [Distributed Mode](/running-amp/distributed-mode#secure-the-deployment).

## Troubleshooting

### `resource_exhausted`

A query needed more memory than `max_mem_mb` or `query_max_mem_mb` allow. Raise them, set `spill_location`, or narrow
the query. For streaming queries, a smaller `microbatch_max_interval` processes fewer blocks at once.

### `deadline_exceeded`

A batch query ran longer than `query_timeout_secs`. Raise it, narrow the query, or run it as a streaming query.

### `failed to bind server to 0.0.0.0:1602`

```
Exiting with error: Server command failed | Caused by: Failed to start server -> failed to initialize server -> failed to bind server to 0.0.0.0:1602 -> Address already in use (os error 48)
```

The number at the end depends on your system: `48` on macOS, `98` on Linux. Another program uses the port. Stop it, or
set [`flight_addr`](/running-amp/configuration-reference#serverflight_addr) to a free one.
