---
title: "Set user, client-id and IP quotas"
description: "Limit producer and consumer byte rates, request percentage and connection creation rate with KafkaQuota, per user, client id or IP."
url: https://monedula.dev/flock/docs/gitops/how-to/set-quotas/
---
Each `KafkaQuota` owns exactly one client quota entity and the limits set on it.

## Before you start

- Apache Kafka or Confluent Platform. `KafkaQuota` does not work on Confluent Cloud ([Supported platforms](/flock/docs/gitops/concepts/supported-platforms/)).
- A connecting principal with `DescribeConfigs` and `AlterConfigs` on the `Cluster` resource, or a super-user.

## Steps

### 1. Limit a user

This quota caps `User:svc-quota-user` at 1 MiB per second for produce traffic and 2 MiB per second for consume traffic. Save it as `manifests/quota.yaml`:

```yaml
apiVersion: gitops.monedula.dev/v1alpha1
kind: KafkaQuota
metadata:
  name: svc-quota
spec:
  clusterRef:
    name: shared
  entity:
    user: "User:svc-quota-user"
  limits:
    producerByteRate: 1048576
    consumerByteRate: 2097152
```

`entity.user` takes the principal form `User:<name>`. monedula-gitops strips the `User:` prefix for Kafka's quota API, so the broker stores the quota for `svc-quota-user`.

### 2. Pick the entity and the limits

The `entity` says whom the quota applies to. It needs at least one component, and it cannot change after creation:

- `user` and `clientId` target a specific user or client id. Set both to target that user and client id together.
- `userDefault: true` and `clientIdDefault: true` target the default entity of that kind. `user` excludes `userDefault`, and `clientId` excludes `clientIdDefault`, but a default combines with a specific value of the other kind.
- `ip` targets one IPv4 or IPv6 address, not a CIDR range or a host name, and `ipDefault: true` targets the IP default. An IP entity is a separate dimension and never combines with a user or client id.

`limits` takes at least one value, and every value must be 0 or more:

- `producerByteRate` and `consumerByteRate` cap produce and fetch throughput in bytes per second.
- `requestPercentage` caps the share of broker request-handler time. It is a percentage that may exceed 100 on brokers with several cores.
- `controllerMutationRate` caps topic and partition creations and deletions, in mutations per second.
- `connectionCreationRate` caps new connections per second. It is valid only on an IP entity, and it is the only limit an IP entity takes.

### 3. Limit connections from an IP address

This quota allows at most 100 new connections per second from `10.0.0.7`. Save it next to the first one, as `manifests/ip-quota.yaml`:

```yaml
apiVersion: gitops.monedula.dev/v1alpha1
kind: KafkaQuota
metadata:
  name: ip-quota
spec:
  clusterRef:
    name: shared
  entity:
    ip: "10.0.0.7"
  limits:
    connectionCreationRate: 100
```

### 4. Apply the quotas

<Tabs group="set-quotas-mode" labels={['CLI', 'Operator']} label="Where you run it">

```bash
monedula-gitops apply -f ./manifests --cluster-config-file ./cluster.yaml
```

```bash
kubectl apply -f manifests/
```

</Tabs>

Setting a quota and changing a limit value need no approval: both are fully reversible.

### 5. Remove a limit

`limits` is authoritative for its entity: a limit that is live on the entity but missing from `limits` is removed. Removing a limit unthrottles clients, so it is [gated](/flock/docs/gitops/concepts/safety-gates/): without approval, `apply` reports the removal as `Blocked`, exits 3 and leaves the limit in place.

<Callout type="warning">
Once approved, removing a key from `limits` deletes that live limit. With the operator, deleting a `KafkaQuota` removes the entity's quota without any approval.
</Callout>

With the CLI, approve the removal with `--allow-destructive`:

```bash
monedula-gitops apply -f ./manifests --cluster-config-file ./cluster.yaml --allow-destructive
```

With the operator, add the annotation `gitops.monedula.dev/allow-destructive: "true"` to the `KafkaQuota`.

The CLI only manages the quota entities that your manifests name. If you remove a `KafkaQuota` from your manifests, its quota stays in Kafka.

## Check it worked

<Tabs group="set-quotas-check" labels={['CLI', 'Operator']} label="Where you run it">

```bash
monedula-gitops verify -f ./manifests --cluster-config-file ./cluster.yaml
```

```bash
kubectl get kafkaquota svc-quota -o jsonpath='{.status.conditions}'
kubectl get kafkaquota ip-quota -o jsonpath='{.status.conditions}'
```

</Tabs>

`verify` exits 0 when the live quotas match the manifests. With the operator, each `KafkaQuota` reports the conditions `Ready` and `QuotaSynced` with the status `True`. The broker now has a quota for the user `svc-quota-user` with `producer_byte_rate=1048576` and `consumer_byte_rate=2097152`, and one for the IP `10.0.0.7` with `connection_creation_rate=100`.

## Related

- The [KafkaQuota reference](/flock/docs/gitops/reference/resources/kafka-quota/) lists every field.
- The [apply command reference](/flock/docs/gitops/reference/cli/apply/) describes `--allow-destructive`.
- Runnable versions: [scenarios/07-user-quota](https://github.com/monedula-dev/monedula-gitops/tree/main/scenarios/07-user-quota) and [scenarios/08-ip-quota](https://github.com/monedula-dev/monedula-gitops/tree/main/scenarios/08-ip-quota)