Grafana Mimir is a horizontally scalable, long-term storage backend for Prometheus metrics. It is fully compatible with the Prometheus remote_write API and PromQL, so you can use it as a drop-in replacement for local Prometheus storage while gaining multi-tenancy, 31-day+ retention, and high availability. This guide covers installing Mimir on Rocky Linux 10 or AlmaLinux 10, configuring it as a single-node deployment, and wiring it up with Grafana Alloy and Grafana.
Prerequisites
Before you begin:
- Rocky Linux 10 or AlmaLinux 10 with root or sudo access
- Grafana Alloy for metrics collection – see Install Grafana Alloy on Rocky Linux / AlmaLinux
- Grafana for dashboards and querying – see Install Prometheus and Grafana on Rocky Linux / AlmaLinux
- SELinux in enforcing mode
Step 1: Download and Install Mimir
Mimir is distributed as a standalone binary. Download the latest release from GitHub:
curl -fsSLo /tmp/mimir https://github.com/grafana/mimir/releases/latest/download/mimir-linux-amd64
Install the binary to /usr/local/bin:
sudo install -m 0755 /tmp/mimir /usr/local/bin/mimir
Verify the installed version:
mimir --version
The output confirms the installed version:
Mimir, version 3.0.4 (branch: HEAD, revision: abcdef123)
Step 2: Create Mimir User and Directories
Create a dedicated system user for Mimir and the storage directories:
sudo useradd --no-create-home --shell /sbin/nologin mimir
Create the data and configuration directories:
sudo mkdir -p /var/lib/mimir/{data,rules,alertmanager}
sudo mkdir -p /etc/mimir
sudo chown -R mimir:mimir /var/lib/mimir
Step 3: Configure SELinux
This is the step that catches most people. When you download a binary to /tmp and copy it to /usr/local/bin, it retains the user_tmp_t SELinux context from /tmp. The system will refuse to execute it. You must set the correct bin_t context on the Mimir binary:
sudo semanage fcontext -a -t bin_t "/usr/local/bin/mimir"
sudo restorecon -v /usr/local/bin/mimir
Verify the context is correct:
ls -Z /usr/local/bin/mimir
The context should show bin_t:
system_u:object_r:bin_t:s0 /usr/local/bin/mimir
Set the correct context on the data directory:
sudo semanage fcontext -a -t var_lib_t "/var/lib/mimir(/.*)?"
sudo restorecon -Rv /var/lib/mimir
Add the SELinux port contexts for Mimir’s HTTP (9009) and gRPC (9097) ports:
sudo semanage port -a -t http_port_t -p tcp 9009
sudo semanage port -a -t http_port_t -p tcp 9097
If semanage is not installed:
sudo dnf install -y policycoreutils-python-utils
Step 4: Configure Mimir
Create the Mimir configuration file. The critical detail here is setting instance_addr and instance_interface_names for every ring component. Mimir uses memberlist rings for coordination, and on cloud VMs or minimal installs, it often picks the wrong interface or fails to resolve its own address. Setting these explicitly on all ring components prevents startup failures.
Open the configuration file:
sudo vi /etc/mimir/config.yml
Add the following configuration:
multitenancy_enabled: false
server:
http_listen_port: 9009
grpc_listen_port: 9097
log_level: info
common:
storage:
backend: filesystem
filesystem:
dir: /var/lib/mimir/data
ingester:
ring:
instance_addr: 127.0.0.1
instance_interface_names:
- lo
kvstore:
store: memberlist
replication_factor: 1
distributor:
ring:
instance_addr: 127.0.0.1
instance_interface_names:
- lo
kvstore:
store: memberlist
compactor:
data_dir: /var/lib/mimir/compactor
sharding_ring:
instance_addr: 127.0.0.1
instance_interface_names:
- lo
kvstore:
store: memberlist
store_gateway:
sharding_ring:
instance_addr: 127.0.0.1
instance_interface_names:
- lo
kvstore:
store: memberlist
replication_factor: 1
ruler:
rule_path: /var/lib/mimir/rules
ring:
instance_addr: 127.0.0.1
instance_interface_names:
- lo
kvstore:
store: memberlist
alertmanager:
data_dir: /var/lib/mimir/alertmanager
sharding_ring:
instance_addr: 127.0.0.1
instance_interface_names:
- lo
kvstore:
store: memberlist
replication_factor: 1
fallback_config_file: /etc/mimir/alertmanager-fallback.yml
memberlist:
join_members: []
blocks_storage:
backend: filesystem
filesystem:
dir: /var/lib/mimir/data/tsdb
tsdb:
dir: /var/lib/mimir/data/tsdb
retention_period: 744h
limits:
max_global_series_per_user: 1500000
ingestion_rate: 50000
ingestion_burst_size: 500000
analytics:
reporting_enabled: false
Note how every ring section includes instance_addr: 127.0.0.1 and instance_interface_names: [lo]. Missing this on even one component causes Mimir to hang during startup while trying to join the ring.
Create the alertmanager fallback config (required even if you do not use alerting):
sudo tee /etc/mimir/alertmanager-fallback.yml > /dev/null <<'ALERT'
route:
receiver: default
receivers:
- name: default
ALERT
Set ownership on the config directory:
sudo chown -R mimir:mimir /etc/mimir
Step 5: Create the Systemd Service
Create a systemd unit file for Mimir:
sudo vi /etc/systemd/system/mimir.service
Add the following service definition:
[Unit]
Description=Grafana Mimir
Documentation=https://grafana.com/docs/mimir/latest/
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=mimir
Group=mimir
ExecStart=/usr/local/bin/mimir -config.file=/etc/mimir/config.yml
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
Reload systemd to pick up the new service:
sudo systemctl daemon-reload
Step 6: Configure Firewall
Open port 9009 for the Mimir HTTP API:
sudo firewall-cmd --permanent --add-port=9009/tcp
sudo firewall-cmd --reload
Verify the port is open:
sudo firewall-cmd --list-ports
Step 7: Start and Enable Mimir
Start the Mimir service:
sudo systemctl enable --now mimir
Check the service status:
sudo systemctl status mimir
Mimir should show active (running):
● mimir.service - Grafana Mimir
Loaded: loaded (/etc/systemd/system/mimir.service; enabled; preset: disabled)
Active: active (running) since Mon 2026-03-24 10:30:45 UTC; 4s ago
Docs: https://grafana.com/docs/mimir/latest/
Main PID: 14567 (mimir)
Tasks: 12 (limit: 23102)
Memory: 128.6M
CPU: 2.345s
CGroup: /system.slice/mimir.service
└─14567 /usr/local/bin/mimir -config.file=/etc/mimir/config.yml
Verify Mimir is ready:
curl -s http://localhost:9009/ready
A healthy instance responds with:
ready
Step 8: Configure Alloy to Send Metrics to Mimir
If you followed the Alloy installation guide, the prometheus.remote_write component already points to http://localhost:9009/api/v1/push. If you are using a standalone Prometheus instance, add the remote_write target to your Prometheus configuration:
sudo vi /etc/prometheus/prometheus.yml
Add the remote_write section:
remote_write:
- url: http://localhost:9009/api/v1/push
Restart Prometheus to apply the change:
sudo systemctl restart prometheus
Step 9: Add Mimir as a Grafana Data Source
In Grafana, go to Connections > Data sources > Add data source and select Prometheus (not a Mimir-specific type – Mimir exposes a Prometheus-compatible API). Set the URL to:
http://localhost:9009/prometheus
The /prometheus path is important – it exposes the PromQL query endpoint. Click Save & test. You should see “Successfully queried the Prometheus API.”
Now you can use standard PromQL queries in Grafana dashboards. For example, to see CPU usage from the system metrics Alloy collects:
100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
Troubleshooting
Mimir fails to start with “exec format error” or “permission denied”
This is almost always an SELinux context issue. The binary still has user_tmp_t from when it was downloaded to /tmp. Fix it:
sudo restorecon -v /usr/local/bin/mimir
If restorecon does not fix it, the fcontext rule may not exist yet. Add it and restore:
sudo semanage fcontext -a -t bin_t "/usr/local/bin/mimir"
sudo restorecon -v /usr/local/bin/mimir
Check for AVC denials:
sudo ausearch -m avc -ts recent | grep mimir
Mimir hangs on startup with ring-related errors
The most common Mimir issue on cloud VMs. Check the journal:
sudo journalctl -u mimir --no-pager -n 30
If you see messages about “waiting for ring” or “instance not found in ring”, it means one or more ring components cannot resolve their own address. Make sure every ring section in /etc/mimir/config.yml has both instance_addr: 127.0.0.1 and instance_interface_names: [lo]. The components that need this are: ingester, distributor, compactor, store_gateway, ruler, and alertmanager.
Mimir returns “per-user series limit exceeded”
The default series limit is conservative. Increase it in the config:
limits:
max_global_series_per_user: 3000000
Restart Mimir after the change. In production, monitor the cortex_ingester_active_series metric to right-size this limit.
Port 9009 blocked by SELinux
If Mimir starts but clients cannot connect, check if SELinux is blocking the port:
sudo ausearch -m avc -ts recent | grep 9009
Add the port context if missing:
sudo semanage port -a -t http_port_t -p tcp 9009
Conclusion
Mimir is now running on Rocky Linux 10 / AlmaLinux 10 as a single-node metrics backend with long-term storage. It accepts Prometheus remote_write from Alloy or Prometheus, serves PromQL queries to Grafana, and handles retention automatically. Combined with Loki for logs and Tempo for traces, this completes the metrics layer of the Grafana LGTM stack.