Comment by cogman10
Historically, -O3 has been a bit less stable (producing incorrect code) and more experimental (doesn't always make things faster).
Flags from -O3 often flow down into -O2 as they are proven generally beneficial.
That said, I don't think -O3 has the problems it once did.
-O3 gained a reputation of being more likely to "break" code, but in reality it was almost always "breaking" code that was invalid to start with (invoked undefined behavior). The problem is C and C++ have so many UB edge cases that a large volume of existing code may invoke UB in certain situations. So -O2 thus had a reputation of being more reliable. If you're sure your code doesn't invoke undefined behavior, though, then -O3 should be fine on a modern compiler.