Not so fast. This next is legal Haskell:
let x = 1
b = x + 2
x = b + x
in <do something with b and x>
The third line creates a second binding of x which shadows the first binding, and shadowing is considered by most people to be within the functional paradigm. What is not considered functional by most people is assigning a variable in a loop although even here you can do it in Haskell. Specifically, you can call readIORef and writeIORef every loop iteration, but last time I tried, that was about 1000 times less efficient than in an imperative language.