I suspect this question arises from the difference in the concept of "variable" in Rust from that in managed languages like Python or Java. In Python, there is an implicit indirection between variable and the object it holds, so:
n = 42
n += 1 # the variable changed, but not the value (here immutable)
# however:
l = []
l.append(42) # the value changed, but not the variable
l = [1, 2, 3] # the variable changed, but not the value
In the second part, the variable l refers to a list object that exists independently of the variable. That object contains both the list elements and the metainformation such as list size. l.append(42) mutates the list object, while l = [1, 2, 3] mutates the variable to refer to a different (freshly created) list object. Multiple variables can easily refer to the same object, which can be a source of bugs.
Languages like Rust and C++ don't work like that. There is no implicit indirection between a variable and the value it contains, variables store the actual value. (Indirections can still exist, but they are either explicit using Box and Rc or hidden in the implementation of the object, as is the case with Vec, but are never provided by the language, they always have to be explicitly requested.) And two variables cannot contain the same object, because the object is the variable. For example:
let mut n = 42;
n += 1; // the contents of the variable changed
// but also:
let mut l = vec![];
l.push(42); // the contents of the variable changed
l = vec![1, 2, 3]; // the contents of the variable changed
In other words, the data that comprises the vector (the triple of <ptr, len, capacity>) is stored in-line in the variable, so every mutation of the vector counts as a modification of the variable. For example, when you append an element to the vector, the vector's length will change, so a piece of data stored directly in l will actually get modified. The only difference between invoking a mut method on l and assigning to l is that in the case of assignment, all fields are likely to change at once. But there is no fundamental difference between the two like there is in Python - both have the effect of modifying the contents stored in the variable. Since variables don't refer to independently-existing objects, the two types of mutation are indistinguishable as far as the language is concerned.
The same applies to the rng variable: it holds an RNG instance whose state must change when you generate the next number. This state change counts as change to the variable, just as does assigning it a brand new RNG. A value in Rust doesn't have inherent "identity" which would distinguish the assignment from other kinds of mutation to the state.
If you wanted to emulate the Python semantics, you could use a smart pointer:
// doesn't need to be mutable, holds reference to heap-allocated RNG
let rng = Rc::new(RefCell::new(thread_rng()));
// RefCell::borrow_mut() grants permission to mutate the shared object,
// but `rng` (the Rc pointer) is still unchanged
let x: u32 = rng.borrow_mut().gen();
// as expected, this wouldn't compile because rng is not mut:
//rng = Rc::new(RefCell::new(thread_rng()));