RabbitMQ
Docker container
Initial users
User management
Tech tutorials

How to add initial users when starting a RabbitMQ Docker container?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

For a fresh RabbitMQ container, the simplest way to create an initial user is through the default user environment variables. The important caveat is that these values are only applied when RabbitMQ is booting with a blank, uninitialized database, so reused volumes often make it look like the settings were ignored.

The Simple Case: One Initial User On First Boot

For development or CI, the official image supports:

bash
1docker run -d \
2  --name rabbitmq \
3  -p 5672:5672 \
4  -p 15672:15672 \
5  -e RABBITMQ_DEFAULT_USER=appuser \
6  -e RABBITMQ_DEFAULT_PASS=strongpassword \
7  -e RABBITMQ_DEFAULT_VHOST=appvhost \
8  rabbitmq:3-management

This creates:

  • the initial user
  • the initial password
  • the initial virtual host

But only if the node is starting from scratch.

That "first boot only" behavior is the most important thing to remember.

Why It Sometimes Seems Not To Work

If you mount a persistent volume and restart the container later, RabbitMQ already has a database. At that point, RABBITMQ_DEFAULT_USER, RABBITMQ_DEFAULT_PASS, and RABBITMQ_DEFAULT_VHOST do not recreate or overwrite users.

That is why this common pattern can confuse people:

yaml
1services:
2  rabbitmq:
3    image: rabbitmq:3-management
4    environment:
5      RABBITMQ_DEFAULT_USER: appuser
6      RABBITMQ_DEFAULT_PASS: strongpassword
7    volumes:
8      - rabbitmq_data:/var/lib/rabbitmq

If rabbitmq_data already contains initialized state, changing the environment variables later will not change the existing users.

For More Than One User, Use Definitions Import

If you need several users, permissions, vhosts, exchanges, or policies at boot time, definitions import is the cleaner approach.

Example definitions.json:

json
1{
2  "users": [
3    {
4      "name": "appuser",
5      "password": "strongpassword",
6      "tags": "administrator"
7    },
8    {
9      "name": "readonly",
10      "password": "readonlypass",
11      "tags": ""
12    }
13  ],
14  "vhosts": [
15    { "name": "appvhost" }
16  ],
17  "permissions": [
18    {
19      "user": "appuser",
20      "vhost": "appvhost",
21      "configure": ".*",
22      "write": ".*",
23      "read": ".*"
24    }
25  ]
26}

Then mount it and point RabbitMQ at it:

yaml
1services:
2  rabbitmq:
3    image: rabbitmq:3-management
4    ports:
5      - "5672:5672"
6      - "15672:15672"
7    volumes:
8      - ./definitions.json:/etc/rabbitmq/definitions.json:ro
9      - ./rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf:ro

And in rabbitmq.conf:

properties
management.load_definitions = /etc/rabbitmq/definitions.json

This is a much better fit when you want reproducible multi-user bootstrapping.

Avoid Shell-Scripting User Creation Inside The Container

A common but fragile pattern is to wrap rabbitmq-server in a shell script, sleep for startup, then run rabbitmqctl add_user .... That can work, but it is harder to reason about, less declarative, and more error-prone than using the official boot-time options.

If you only need one default user, use the environment variables. If you need a full preconfigured broker, use definitions import.

That split keeps the setup maintainable.

It also makes local debugging easier because you know whether the source of truth is a few environment variables or a full declarative broker definition.

That clarity saves time when containers are recreated frequently.

It helps during CI too.

Common Pitfalls

One common mistake is expecting RABBITMQ_DEFAULT_USER and related variables to change an already-initialized volume.

Another issue is using these defaults in production as if they were a full identity-management strategy. They are mainly convenient for development, CI, and controlled bootstrap scenarios.

A third problem is trying to add many users through ad hoc container startup scripts when a definitions file would be clearer and more reproducible.

Finally, people often forget that users also need permissions on the relevant virtual hosts, not just an account record.

Summary

  • 'RABBITMQ_DEFAULT_USER, RABBITMQ_DEFAULT_PASS, and RABBITMQ_DEFAULT_VHOST work only on first boot of a blank node.'
  • Persistent volumes are the usual reason those variables appear to stop working.
  • For multiple users and richer setup, use definitions import instead of shell scripting.
  • Mount definitions.json and point management.load_definitions to it for reproducible bootstrapping.
  • Always think about permissions and vhosts, not just usernames and passwords.
  • Decide early whether startup convenience or reproducible provisioning matters more.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.