Start with a functor--a parameterized type with fmap. Maybe t, Either e t, [t], IO t, State s t, and so on.
Consider a monad m and a function, a -> m b. Frequently you want to feed another monadic value, m a, into that function.
A monad gives you a function, >>=, that lets you take m a and feed it into a -> m b.
So any function that does IO, that looks like a -> IO b, you can take an IO a and plug it into a -> IO b. Any function that manipulates a state, you can take State a and plug it into a -> State b. This is the heart of a monad: gluing monadic functions together.
The meaning of >>= depends on the monad you're in. You also need return :: a -> m a, which can take a thing and put it in a monadic value.
There are monad laws also. A lot of times there's several ways to manipulate monads to do something, and the laws are needed to make sure they're all equivalent. For everyday monad use the laws aren't terribly important to remember, and GHC's linter will helpfully point out when you can use them.
That's my attempt at a short explanation. The "monad tutorial problem" has been weighing on my mind. The only way I ever understood monads was by reading and rereading the definition and examples. Tutorials never taught me anything.