---
title: "Tuning Voyager behavior"
description: "Change how Aerospike Voyager reads, writes, queries, and connects to a cluster, and understand how Voyager respects a role's read quota."
---

# Tuning Voyager behavior

> For the complete documentation index see: [llms.txt](https://aerospike.com/docs/llms.txt)
> 
> All documentation pages available in markdown.

A query gives up before it finishes. A scan slows down a cluster other people are using. A rate quota rejects your scans outright. A deleted record reappears after a restart. Each of those is something you change on the **Policies** page, one cluster at a time.

Voyager reaches your cluster through the same Aerospike client your application uses, so these settings are the standard client policies rather than a Voyager invention. Changing them here changes how Voyager behaves against that one connection, and leaves your application untouched.

## Prerequisites

-   Aerospike Voyager 0.2.6 or later.
-   A saved, connected cluster. See [Connecting to clusters](https://aerospike.com/docs/database/tools/voyager/guides/connecting).
-   The read quota behavior requires Aerospike Database Enterprise Edition with security and rate quotas enabled.

## What do you want to change?

| Goal | Setting |
| --- | --- |
| Let a slow scan or query run longer | [Query / scan](#query--scan-policy) > Total timeout |
| Stop a scan from loading a cluster other people are using | [Query / scan](#query--scan-policy) > Records per second |
| Run scans when a role read quota is rejecting them | [How Voyager respects a read quota](#how-voyager-respects-a-read-quota) |
| Let a single-record read run longer | [Read](#read-policy) > Total timeout |
| Retry a read that failed on a busy node | [Read](#read-policy) > Max retries |
| Keep deleted records from reappearing after a cold restart | [Write](#write-policy) > Durable delete |
| Store the user key with records so reads return it | [Write](#write-policy) > Send key |
| Decide what happens when writing to a key that already exists | [Write](#write-policy) > Record exists action |
| Change how long Voyager waits when dialing a cluster | [Connect](#connect-policy) > Connection timeout |
| Read from same-rack nodes | [Connect](#connect-policy) > Rack aware |

Settings that apply to Voyager as a whole, such as how many records a page shows or whether usage analytics are sent, live in [Settings and preferences](https://aerospike.com/docs/database/tools/voyager/guides/settings) instead.

## Open the Policies page

1.  Click the sliders icon at the bottom of the sidebar.
    
    Voyager opens a cluster overview listing every saved connection, with its server version, cluster size, connection status, and a count of policy areas.
    
2.  Click a cluster card.
    
    The page header reads **Policies for** followed by the cluster name. Cards for disconnected clusters are inactive, so [connect](https://aerospike.com/docs/database/tools/voyager/guides/connecting) the cluster first.
    

  ![Policies overview listing a card for the enterprise-policies-test cluster, next to the sidebar with the Policies sliders icon highlighted](https://aerospike.com/docs/_astro/policies_cluster_overview.Bk6VwYEs_ZPjuY3.png) ![Policies for enterprise-policies-test, with the Search policies box, the refresh icon, and the Read policy card showing Total timeout, Socket timeout, and Max retries above a collapsed Advanced options toggle](https://aerospike.com/docs/_astro/policies_cluster_page.B-tjVWUY_Z29xYBh.png)

Two controls apply to the whole page:

-   **Search policies** filters by label, description, and field name across all five groups. Groups with no match are hidden, and matching advanced fields are revealed automatically.
-   The refresh icon, beside **Last updated**, refetches this connection’s saved values and re-reads your role quota from the cluster.

 ![Searching for timeout filters the page to matching fields in every group and reveals the matching advanced fields, such as Timeout delay under Read policy](https://aerospike.com/docs/_astro/policies_search_timeout.D05HkDPH_1T6x0r.png)

Each group shows its common fields first, with the rest behind an **Advanced options** toggle that reports how many fields it holds.

## What each group applies to

| Group | Applied to | When a change takes effect |
| --- | --- | --- |
| Read policy | Single-record reads and batch reads | Next operation |
| Write policy | Record writes and deletes | Next operation |
| Query / scan policy | Scans and secondary-index queries in the data browser | Next operation |
| Connect policy | Client settings used when dialing the cluster | Next time this connection reconnects |
| Info policy | Cluster info commands | Next time this connection reconnects |

These are standard Aerospike client policies. Voyager has no policy system of its own: it talks to your cluster through the same Aerospike client your application uses, and this page is where you set that client’s policies per connection. [Policies](https://aerospike.com/docs/database/learn/policies) defines the command policies, and the [Connection tuning guide](https://aerospike.com/docs/develop/connection-tuning-guide) defines the connection-pool and timeout parameters. In the following tables, a linked setting name points to its canonical definition, and the **Effect** column states what the setting changes about Voyager’s operations. A setting without a link has no canonical page of its own, so its **Effect** entry is the definition.

## Read policy

Change these when individual record lookups time out, fail on a busy node, or need to come from a particular replica. Applied to single-record reads and batch reads.

| Setting | Control | Unit | Default | Valid values | Effect |
| --- | --- | --- | --- | --- | --- |
| [Total timeout](https://aerospike.com/docs/database/learn/policies#total-timeout) | Number | ms | 1000 | 0 to 3600000, 0 = no limit | Total time budget for the read command across all attempts. |
| [Socket timeout](https://aerospike.com/docs/database/learn/policies#socket-timeout) | Number | ms | 30000 | 0 to 3600000, 0 = no limit | Time budget for a single attempt on the socket. |
| [Max retries](https://aerospike.com/docs/database/learn/policies#max-retries) | Number | count | 2 | 0 to 100 | How many retries Voyager makes before aborting. The initial attempt is not counted. |

### Read policy advanced options

| Setting | Control | Unit | Default | Valid values | Effect |
| --- | --- | --- | --- | --- | --- |
| [Send key](https://aerospike.com/docs/database/learn/policies#send-key) | Switch | n/a | Off | On, Off | Sends the user key on reads. Rarely needed. |
| [Replica policy](https://aerospike.com/docs/database/learn/policies#replica) | Dropdown | n/a | Sequence | Master, Master + replicas, Sequence, Prefer rack, Random | Which node serves the read. |
| [Read mode (AP)](https://aerospike.com/docs/database/learn/policies#ap-read-mode) | Toggle group | n/a | One | One, All | Read mode used in availability (AP) namespaces. |
| [Read mode (SC)](https://aerospike.com/docs/database/learn/policies#sc-read-mode) | Dropdown | n/a | Session | Session, Linearize, Allow replica, Allow unavailable | Read mode used in [strong consistency](https://aerospike.com/docs/database/learn/strong-consistency) (SC) namespaces. |
| [Sleep between retries](https://aerospike.com/docs/database/learn/policies#sleep-between-retries) | Number | ms | 1 | 0 to 3600000 | Delay inserted between retries. Ignored when **Max retries** is 0. |
| Use compression | Switch | n/a | Off | On, Off | Compresses command buffers. Enterprise Edition only. |
| [Read touch TTL percent](https://aerospike.com/docs/database/learn/policies#expiration-time-to-live) | Number | percent | 0 | \-1 to 100 | Resets a record’s TTL on read when the remaining TTL is within this percent of the last write TTL. 0 uses the server default, and -1 never touches. |
| Exit fast on exhausted pool | Switch | n/a | Off | On, Off | Fails immediately instead of waiting when the connection pool is exhausted. |
| [Timeout delay](https://aerospike.com/docs/develop/connection-tuning-guide#timeoutdelay) | Number | ms | 0 | 0 to 3600000, 0 = disabled | Delay before background socket recovery starts after a read timeout. |

The namespace’s server-side [strong consistency](https://aerospike.com/docs/database/learn/strong-consistency) configuration decides which read mode governs a read: a read in an availability namespace uses **Read mode (AP)**, and a read in a strong consistency namespace uses **Read mode (SC)**. Set both when your connections span both namespace types.

## Write policy

Change these when you need deletes to survive a cold restart, want the user key stored with the record, or need to control what happens when a key already exists. Applied to record writes and deletes.

An Aerospike role can also carry a [write rate quota](https://aerospike.com/docs/database/learn/security/rate-quotas). The server enforces it on every write and delete, and the Aerospike client offers no write rate control, so a **Rate quota exceeded** error on a write means the edit rate passed the role’s quota. Space out edits, or ask an administrator to raise the quota.

| Setting | Control | Unit | Default | Valid values | Effect |
| --- | --- | --- | --- | --- | --- |
| [Send key](https://aerospike.com/docs/database/learn/policies#send-key) | Switch | n/a | On | On, Off | Stores the user key alongside the record so it can be retrieved later. |
| [Record exists action](https://aerospike.com/docs/database/learn/policies#write-mode) | Dropdown | n/a | Update | Update, Update only, Replace, Replace only, Create only | Behavior when writing to a key that already exists. |
| [Durable delete](https://aerospike.com/docs/database/learn/architecture/durable-deletes) | Switch | n/a | Off | On, Off | Writes a tombstone for deleted records. Enterprise Edition only. |
| [Expiration](https://aerospike.com/docs/database/learn/policies#expiration-time-to-live) | Number | seconds | 0 | 0 to 4294967295 | Record TTL. 0 uses the namespace default, 4294967295 never expires, 4294967294 keeps the record’s existing TTL. |
| [Total timeout](https://aerospike.com/docs/database/learn/policies#total-timeout) | Number | ms | 1000 | 0 to 3600000, 0 = no limit | Total time budget for the write command across all attempts. |
| [Socket timeout](https://aerospike.com/docs/database/learn/policies#socket-timeout) | Number | ms | 30000 | 0 to 3600000, 0 = no limit | Time budget for a single attempt on the socket. |
| [Max retries](https://aerospike.com/docs/database/learn/policies#max-retries) | Number | count | 0 | 0 to 100 | How many retries Voyager makes before aborting. Writes default to 0 because they are not idempotent. |

::: caution
Two write fields change durability and correctness, so change them deliberately:

-   **Durable delete** requires Enterprise Edition. On Community Edition the tombstone is not written, and deleted records can return after a cold restart.
-   **Max retries** defaults to 0 for writes because a write is not idempotent. Raising it means a write that times out after the server applied it can be applied a second time.
:::

### Write policy advanced options

| Setting | Control | Unit | Default | Valid values | Effect |
| --- | --- | --- | --- | --- | --- |
| [Generation policy](https://aerospike.com/docs/database/learn/policies#write-generation-policy) | Dropdown | n/a | None | None, Expect generation equal, Expect generation greater | Restricts the write by record generation. |
| [Commit level](https://aerospike.com/docs/database/learn/policies#write-commit-level) | Toggle group | n/a | All replicas | All replicas, Master only | Consistency guarantee required before the write is acknowledged. |
| [Sleep between retries](https://aerospike.com/docs/database/learn/policies#sleep-between-retries) | Number | ms | 1 | 0 to 3600000 | Delay inserted between retries. Ignored when **Max retries** is 0. |
| Use compression | Switch | n/a | Off | On, Off | Compresses command buffers. Enterprise Edition only. |
| Exit fast on exhausted pool | Switch | n/a | Off | On, Off | Fails immediately instead of waiting when the connection pool is exhausted. |
| [Timeout delay](https://aerospike.com/docs/develop/connection-tuning-guide#timeoutdelay) | Number | ms | 0 | 0 to 3600000, 0 = disabled | Delay before background socket recovery starts after a write timeout. |

## Query / scan policy

Change these when a scan is too slow, is loading a shared cluster too heavily, or is being rejected by a rate quota. Applied to scans and secondary-index queries when browsing records.

| Setting | Control | Unit | Default | Valid values | Effect |
| --- | --- | --- | --- | --- | --- |
| Records per second | Number | records/sec per node | 0 | 0 to 100000000 | Throttles how many records each server node returns per second. 0 lets the server decide: no client limit, or your role’s read quota when one is set. See [How Voyager respects a read quota](#how-voyager-respects-a-read-quota). |
| [Total timeout](https://aerospike.com/docs/database/learn/policies#total-timeout) | Number | ms | 0 | 0 to 3600000, 0 = no limit | Overall deadline for a scan or query, including retries. |

### Query / scan policy advanced options

| Setting | Control | Unit | Default | Valid values | Effect |
| --- | --- | --- | --- | --- | --- |
| [Socket timeout](https://aerospike.com/docs/database/learn/policies#socket-timeout) | Number | ms | 30000 | 0 to 3600000, 0 = no limit | Time budget for a single attempt on the socket. |
| [Max retries](https://aerospike.com/docs/database/learn/policies#max-retries) | Number | count | 5 | 0 to 100 | How many retries Voyager makes before aborting the scan or query. The initial attempt is not counted. |
| Max concurrent nodes | Number | count | 0 | 0 to 10000, 0 = all nodes | How many server nodes are queried in parallel. Lower this to spread a large scan over time. |
| Expected duration | Dropdown | n/a | Long | Long, Short, Long (relax AP) | Tells the server how long the query is expected to run so it can schedule resources. |

## Connect policy

Client settings applied when dialing the cluster. Changes take effect the next time this connection reconnects.

These fields are the defaults Voyager dials with. An individual connection carries its own **Timeout** and **Login timeout** fields in the [connection dialog](https://aerospike.com/docs/database/tools/voyager/guides/connecting#connection-and-login-timeouts), which override these defaults and accept a wider range. The Aerospike client itself sets no upper bound on either value. The ranges in the following table are what this page accepts.

| Setting | Control | Unit | Default | Valid values | Effect |
| --- | --- | --- | --- | --- | --- |
| [Connection timeout](https://aerospike.com/docs/develop/connection-tuning-guide#connecttimeout) | Number | seconds | 30 | 1 to 3600 | Time allowed for the initial connection. A timeout set on an individual [connection](https://aerospike.com/docs/database/tools/voyager/guides/connecting#connection-and-login-timeouts) overrides this default. |
| [Use services alternate](https://aerospike.com/docs/database/tools/voyager/guides/connecting#services-alternate) | Switch | n/a | Off | On, Off | Uses the services-alternate addresses advertised during cluster tend, for cloud and Kubernetes deployments. A value set on the connection itself overrides this default. |

### Connect policy advanced options

| Setting | Control | Unit | Default | Valid values | Effect |
| --- | --- | --- | --- | --- | --- |
| Login timeout | Number | seconds | 10 | 0 to 3600, 0 = client default | Time allowed for [external (LDAP) login](https://aerospike.com/docs/database/tools/voyager/guides/connecting#authentication-modes). A value set on the connection overrides this default. |
| Cluster name | Text | n/a | empty | Any cluster ID | Expected cluster ID. Nodes must report this name to join the client’s view of the cluster. Leave blank to skip the check. |
| [Idle timeout](https://aerospike.com/docs/develop/connection-tuning-guide#maxsocketidle) | Number | seconds | 0 | 0 to 3600, 0 = client default | Closes and discards a connection after this much idle time. On a cluster that sets `proto-fd-idle-ms`, set this a few seconds lower than that value so Voyager discards idle connections before the server reaps them. Server 8.1 and later deprecate `proto-fd-idle-ms`. |
| [Tend interval](https://aerospike.com/docs/develop/connection-tuning-guide#tendinterval) | Number | ms | 1000 | 10 to 3600000 | How often the client polls the cluster for state changes. |
| Config interval | Number | seconds | 5 | 0 to 3600 | How often the client checks for configuration changes. |
| [Connection queue size](https://aerospike.com/docs/develop/connection-tuning-guide#maxconnspernode-asyncmaxconnspernode) | Number | count | 100 | 1 to 100000 | Size of the per-node connection queue cache. |
| [Min connections per node](https://aerospike.com/docs/develop/connection-tuning-guide#minconnspernode) | Number | count | 0 | 0 to 100000 | Connections preallocated to each node. |
| Opening connection threshold | Number | count | 0 | 0 to 100000, 0 = no limit | Ceiling on connections being opened in parallel. |
| [Max error rate](https://aerospike.com/docs/develop/connection-tuning-guide#maxerrorrate) | Number | count | 100 | 0 to 1000000, 0 = disabled | Errors allowed per node per error-rate window before the circuit breaker trips. |
| [Error rate window](https://aerospike.com/docs/develop/connection-tuning-guide#errorratewindow) | Number | tend iterations | 1 | 1 to 100 | Length of the circuit-breaker error window, measured in tend iterations. |
| Fail if not connected | Switch | n/a | On | On, Off | Fails client creation when no seed host can be reached. |
| [Limit connections to queue size](https://aerospike.com/docs/develop/connection-tuning-guide#maxconnspernode-asyncmaxconnspernode) | Switch | n/a | On | On, Off | Caps open connections per node at the connection queue size. |
| [Rack aware](https://aerospike.com/docs/database/learn/architecture/clustering/rack-aware) | Switch | n/a | Off | On, Off | Tracks rack information and prefers same-rack nodes for reads. Use with the **Prefer rack** replica policy. |
| Rack IDs | Text | n/a | empty | Comma-separated integers, for example `1, 2, 3` | Preferred rack IDs in order of preference. Requires **Rack aware**. |
| Seed only cluster | Switch | n/a | Off | On, Off | Uses only the seed addresses and skips peer discovery. |
| Ignore other subnet aliases | Switch | n/a | Off | On, Off | Ignores node aliases outside the main subnet. |
| Application ID | Text | n/a | empty | Any identifier | Correlates this client’s operations with server-side metrics. |

## Info policy

Change this when cluster statistics are slow to load. Applied to cluster info commands.

| Setting | Control | Unit | Default | Valid values | Effect |
| --- | --- | --- | --- | --- | --- |
| Info timeout | Number | ms | 2000 | 0 to 3600000 | Socket timeout for cluster info commands. Any remaining request deadline still applies. |

## How values are stored and resolved

Every field on the Policies page belongs to the connection you have open. Voyager resolves each field in this order and uses the first value it finds:

1.  The value saved on this connection.
2.  The global value, where one exists. **Preferences > Advanced > Connection settings** holds the global values, and it covers the Connect and Info groups only.
3.  The built-in default listed in the preceding tables.

Read, Write, and Query / scan fields have no global tier. Those are set per connection, so applying the same read timeout to several clusters means setting it on each one.

A field you have never edited on this connection is unset at connection scope, so the global value or the built-in default applies. Editing the field on the Policies page writes a connection-scoped value that from then on wins over the global one for that connection only. Other connections are unaffected.

Separately, several numeric fields treat `0` as a sentinel meaning “no client-side limit” or “use the server default.” The **Valid values** column in the preceding tables states what `0` means for each field.

**Edits save automatically.** There is no Save button. Voyager batches edits made in quick succession and writes them to the connection a fraction of a second after you stop typing.

**Values are validated as you type.** A number outside its valid range shows an inline error and is not saved, so the last valid value stays in effect until you correct the entry. Text fields validate the same way: **Rack IDs**, for example, rejects anything that is not a comma-separated list of integers.

::: note
Connect and info changes are stored immediately but are not applied to a live session. Disconnect and reconnect the cluster to pick them up.
:::

## How Voyager respects a read quota

An Aerospike role can carry a rate quota that limits how many records per second a user reads. When the connected user’s role has a read quota, Voyager keeps its query rate within that limit instead of letting the server reject the work.

**Records per second** in the **Query / scan** group drives this behavior:

| Your setting | Effect under a read quota of 200 records per second |
| --- | --- |
| Unset, or `0` | Voyager requests the full quota, 200 records per second. This leaves no headroom, so the scan is rejected if the user has any other read activity. |
| A value below the quota, such as `150` | Voyager keeps your value and runs at 150 records per second. |
| A value above the quota | Rejected. Voyager reports the maximum you can set. |

`0` does not mean unthrottled when you have a quota, and it is not the safest setting. Voyager fills in your full quota, and the server admits a scan only when the requested rate, your current transaction rate, and the rate of any queries already running all fit inside the quota. Requesting the whole quota leaves nothing for the rest, so set an explicit value below the quota whenever this user does anything else against the cluster.

**How the cap is discovered.** When the Policies page loads for a cluster, and again each time you click the refresh icon, Voyager looks up the user named on that connection and reads its effective read quota from the cluster. A user’s effective quota is the largest read quota among that user’s roles, and it applies at each server node. See [Rate quotas](https://aerospike.com/docs/database/learn/security/rate-quotas) for the full model.

**The cap is enforced, not advisory.** With a cap in place:

-   The field does not accept a value above the quota. Typing one shows `Maximum is N (your role's read quota). Choose N or lower.` and the value is not saved.
-   The increment control stops at the quota.
-   A badge reads **Uses role limit** while the field is 0, and **At role limit** once the value reaches the quota.
-   The field description states the quota and the range you can choose from.

  ![Records per second at 0 with an orange Uses role limit badge and the caption Your role's read quota caps this at 200 rec/sec](https://aerospike.com/docs/_astro/records_per_second_role_limit.DFNPZAnR_ZVHH8V.png) ![Records per second showing 250 outlined in red with the error Maximum is 200 (your role's read quota). Choose 200 or lower.](https://aerospike.com/docs/_astro/records_per_second_over_quota_error.BzGqSLjp_Z1PGTin.png)

**When there is no cap.** Voyager shows no cap and leaves the field’s full range available when any of the following is true:

-   The connection has no username saved.
-   The cluster reports that security is not enabled.
-   The connected user is not permitted to read its own quota, or the lookup fails for any other reason.

In the last case, a quota might still be enforced by the server even though Voyager cannot display it. Set **Records per second** manually to a value at or below the quota your administrator assigned.

**If a scan is rejected with a rate-quota error**, set **Records per second** below your quota. The server admits a scan only when its requested rate, together with your other read activity, stays inside the quota, so a value with headroom is what lets it run. A value like three quarters of the quota saves automatically and applies to the next scan.

 ![Query / scan policy with Records per second set to 150 and the caption noting the 200 rec/sec role quota](https://aerospike.com/docs/_astro/records_per_second_150_saved.g1ZbyTR-_K2eX0.png)

**If your quota changes on the server**, click the refresh icon on the Policies page so Voyager re-reads it. Voyager sends a stored value greater than 0 to the server exactly as saved, so a value saved before an administrator lowered your quota keeps failing until you lower the field to the new limit. The field’s validation message states the new maximum after a refresh.

::: note
The server’s `records_per_second` field has an effective lower limit of 100. Values below 100 are accepted without an error but do not slow a scan below that rate. On a quota near or below 100, no client-side value gives you headroom, so a rejected scan needs a higher quota rather than a lower setting. See [Rate quotas](https://aerospike.com/docs/database/learn/security/rate-quotas).
:::

## Verify

Confirm a policy took effect any of these ways:

-   Reopen the field on the **Policies** page and check the stored value.
-   For a read quota, check that the field shows the quota note, and that the **Uses role limit** or **At role limit** badge matches what you set.
-   Confirm the quota the server holds with [Aerospike Admin (asadm)](https://aerospike.com/docs/database/tools/asadm): run `show users` in the asadm shell and read the quota column for the connected user.

## Troubleshoot

| Symptom | Cause | Fix |
| --- | --- | --- |
| **Rate quota exceeded** on a scan or query | The requested rate, together with your other read activity, passed the role’s read quota | Set **Records per second** below your quota, or ask an administrator to raise the quota. |
| **Rate quota exceeded** on a write or delete | The edit rate passed the role’s write quota, which has no client-side control | Space out edits, or ask an administrator to raise the quota. |
| **Quotas not enabled** | The cluster does not have rate quotas enabled | Enable quotas in the Aerospike server configuration. |
| **Insufficient permissions** | The connected user’s role lacks a required privilege | Connect as a user whose role carries the privilege, or ask an administrator to grant it. |
| No quota note appears on a cluster that has one | Voyager could not read the quota for the connected user | Verify the connection authenticates as a named user and that the user’s role carries a read quota, then click the refresh icon. |
| A saved **Records per second** value starts failing | An administrator lowered the quota below your saved value | Click the refresh icon so Voyager picks up the new limit, then lower the field below the new quota. Clearing the field to `0` does not recover it, because `0` requests the full quota and leaves no headroom. |

For other problems, see [Voyager troubleshooting](https://aerospike.com/docs/database/tools/voyager/troubleshooting).

## Next steps

-   [Settings and preferences](https://aerospike.com/docs/database/tools/voyager/guides/settings)
-   [Connecting to clusters](https://aerospike.com/docs/database/tools/voyager/guides/connecting)
-   [Browsing data](https://aerospike.com/docs/database/tools/voyager/guides/browsing-data)
-   [Rate quotas](https://aerospike.com/docs/database/learn/security/rate-quotas)
-   [Troubleshooting](https://aerospike.com/docs/database/tools/voyager/troubleshooting)