Scenario 13.2.1 · Reset offsets the right way
Reset Kafka consumer group offsets with --to-earliest
A reset is stop, reset, start: it refuses a live group whether or not you pass --execute, the dry run is the default, and the replay is visible on the canvas.
Run this scenario in the playgroundOne group, one member, nothing to read. t+0.000s
Open the terminal with Ctrl and the backtick key (on a phone, the "..." menu). `kafka-consumer-groups --list` finds the one group, and `kafka-consumer-groups --describe --group g1` shows it before a single record exists: one member owns the partition, the log end is zero, and CURRENT-OFFSET and LAG read as dashes because this group has never committed anything.
Open at this step: step 1, One group, one member, nothing to readEight records read, and a reset that will not run. t+3.000s
`kafka-consumer-groups --describe --group g1` shows the group level with the end of the log. Now try the reset twice and read the ANSWER rather than the flag: `kafka-consumer-groups --reset-offsets --group g1 --topic orders --to-earliest --dry-run` and `kafka-consumer-groups --reset-offsets --group g1 --topic orders --to-earliest --execute` are refused with the same line, because the group's state is checked before any plan is computed.
Open at this step: step 2, Eight records read, and a reset that will not runThe consumer is stopped, so the group is Empty. t+3.600s
`kafka-consumer-groups --describe --group g1 --state` now reports Empty with no members, and `kafka-consumer-groups --describe --group g1` shows the committed offsets the stopped app left behind. The same dry run is allowed here: `kafka-consumer-groups --reset-offsets --group g1 --topic orders --to-earliest --dry-run` prints the offset it WOULD write and changes nothing, which is what you get when you leave the flag off. Then `kafka-consumer-groups --reset-offsets --group g1 --topic orders --to-earliest --execute` does it for real - and the scenario does exactly that on the next tick, so pressing it forks the sandbox onto the same three actions.
Open at this step: step 3, The consumer is stopped, so the group is EmptyBack at the bottom of the log. t+4.400s
The reset landed and the first commit after it has settled, so there is a number to read again: `kafka-consumer-groups --describe --group g1` has the group down near the START of a log it had already finished, with LAG most of the way back up. `kafka-get-offsets --topic orders --time earliest` says why that is where it went - nothing has been deleted, so the earliest offset in this log is still 0.
Open at this step: step 4, Back at the bottom of the logClimbing back up. t+4.600s
One poll later the group has moved: `kafka-consumer-groups --describe --group g1` shows CURRENT-OFFSET higher and LAG smaller than on the previous frame, which is the replay in progress. `kafka-consumer-groups --describe --group g1 --members --verbose` shows the member owning the same partition. The simulator brings back the same member id; a real restarted consumer joins with a new one (only a static group.instance.id carries over). The reset itself rewrites committed offsets and nothing else.
Open at this step: step 5, Climbing back upBack at the end of the log, the long way round. t+5.400s
The replay is finished and `kafka-consumer-groups --describe --group g1` reads exactly as it did before the reset. `kafka-get-offsets --topic orders --time latest` asks the log itself where it ends, with no consumer group involved, and answers with the same number the lag table's LOG-END-OFFSET column is showing.
Open at this step: step 6, Back at the end of the log, the long way roundReading live again. t+6.800s
A ninth record arrived after the replay and the group consumed it in stride. `kafka-consumer-groups --describe --group g1` has LAG back at zero against a log end one record higher, and `kafka-consumer-groups --describe --group g1 --state` is Stable with one member - the group is doing its normal job again, from an offset you chose.
Open at this step: step 7, Reading live againWhat you start with
This scenario is played from the terminal (Ctrl and the backtick key). Resetting a consumer group is the most common destructive-looking operation on a running Kafka cluster, and the tool refuses to do it while the group still has a live member - for good reason. Here the group reads a topic, the consumer is stopped, the reset runs, and the group replays the whole log from the beginning.
Step by step
- One group, one member, nothing to read t+0.000s Open the terminal with Ctrl and the backtick key (on a phone, the "..." menu). `kafka-consumer-groups --list` finds the one group, and `kafka-consumer-groups --describe --group g1` shows it before a single record exists: one member owns the partition, the log end is zero, and CURRENT-OFFSET and LAG read as dashes because this group has never committed anything. Open at this step: step 1, One group, one member, nothing to read
- Eight records read, and a reset that will not run t+3.000s `kafka-consumer-groups --describe --group g1` shows the group level with the end of the log. Now try the reset twice and read the ANSWER rather than the flag: `kafka-consumer-groups --reset-offsets --group g1 --topic orders --to-earliest --dry-run` and `kafka-consumer-groups --reset-offsets --group g1 --topic orders --to-earliest --execute` are refused with the same line, because the group's state is checked before any plan is computed. Open at this step: step 2, Eight records read, and a reset that will not run
- The consumer is stopped, so the group is Empty t+3.600s `kafka-consumer-groups --describe --group g1 --state` now reports Empty with no members, and `kafka-consumer-groups --describe --group g1` shows the committed offsets the stopped app left behind. The same dry run is allowed here: `kafka-consumer-groups --reset-offsets --group g1 --topic orders --to-earliest --dry-run` prints the offset it WOULD write and changes nothing, which is what you get when you leave the flag off. Then `kafka-consumer-groups --reset-offsets --group g1 --topic orders --to-earliest --execute` does it for real - and the scenario does exactly that on the next tick, so pressing it forks the sandbox onto the same three actions. Open at this step: step 3, The consumer is stopped, so the group is Empty
- Back at the bottom of the log t+4.400s The reset landed and the first commit after it has settled, so there is a number to read again: `kafka-consumer-groups --describe --group g1` has the group down near the START of a log it had already finished, with LAG most of the way back up. `kafka-get-offsets --topic orders --time earliest` says why that is where it went - nothing has been deleted, so the earliest offset in this log is still 0. Open at this step: step 4, Back at the bottom of the log
- Climbing back up t+4.600s One poll later the group has moved: `kafka-consumer-groups --describe --group g1` shows CURRENT-OFFSET higher and LAG smaller than on the previous frame, which is the replay in progress. `kafka-consumer-groups --describe --group g1 --members --verbose` shows the member owning the same partition. The simulator brings back the same member id; a real restarted consumer joins with a new one (only a static group.instance.id carries over). The reset itself rewrites committed offsets and nothing else. Open at this step: step 5, Climbing back up
- Back at the end of the log, the long way round t+5.400s The replay is finished and `kafka-consumer-groups --describe --group g1` reads exactly as it did before the reset. `kafka-get-offsets --topic orders --time latest` asks the log itself where it ends, with no consumer group involved, and answers with the same number the lag table's LOG-END-OFFSET column is showing. Open at this step: step 6, Back at the end of the log, the long way round
- Reading live again t+6.800s A ninth record arrived after the replay and the group consumed it in stride. `kafka-consumer-groups --describe --group g1` has LAG back at zero against a log end one record higher, and `kafka-consumer-groups --describe --group g1 --state` is Stable with one member - the group is doing its normal job again, from an offset you chose. Open at this step: step 7, Reading live again
The takeaway
A reset is stop, reset, start. The tool will not do the stopping for you: it checks the group state first, and a group with any live member is refused before a plan is even computed, so passing --execute changes nothing about that answer. Once the group is Empty the same command prints the offsets it would move - that is the DEFAULT, and it is free - and only --execute writes the new offsets - here the sandbox also brings the member back in the same step, where on a real cluster you restart the application yourself. What the canvas then shows is a genuine replay: the group re-reads every record it had already committed, and carries straight on into the new ones.
Configs in this scenario
-
group.Makes the consumer a static member: after a restart within the session timeout it gets its partitions back without a rebalance, and only one member with this id can be in the group at a time.instance. id
Embed this scenario
Paste this into a blog post, a course page or your team's docs. The scenario plays inside your page, and the link under it points readers to this walkthrough.
<iframe src="https://monedula.dev/kafka-simulator/embed/?scenario=13.2.1" title="Kafka Simulator: Reset offsets the right way" width="100%" height="520" style="border:1px solid #d0d0d0;border-radius:8px" loading="lazy"></iframe>
<p><a href="https://monedula.dev/kafka-simulator/scenarios/reset-offsets/">Reset Kafka consumer group offsets with --to-earliest</a></p> Further reading
More in Terminal ops
- Kafka from the terminal: hosts, ssh and the KRaft controller
- Diagnose consumer lag with kafka-consumer-groups --describe
- Kafka log segments on disk: leader vs follower
- Under-replicated vs under-min-ISR partitions in Kafka
- Set retention.ms on a live topic with kafka-configs
- Kafka partition reassignment: execute, throttle, verify
- Graceful broker shutdown with kafka-server-stop
- Kafka tools on two clusters: --bootstrap-server decides