It's an universal truth: if you want to keep something from jamming up, you need to exercise it. It's true for the human body, for machine parts and for protocol features.
HTTP was at 1.1 for a very long time but it appears the upgrade to version 2 is going fine. What is the difference here? The protocol version exchange mechanism?
The HTTP 1.1 to 2 upgrade is only going fine due to massive work (mostly by Google) over a period of years. HTTP/2 was also able to benefit from a lot of pain that SPDY and WebSockets went through earlier. Protocol ossification is still a hard problem.
IIRC WebSockets has basically nothing to do with the way http2 is handled, and websockets are still going over a simple HTTP1.1 Connect/Upgrade. What is the connection between websockets and http2?
HTTP/2 doesn't have the same problems because it requires TLS+ALPN, but IIRC that "clean" solution was only arrived at after years of discussion and experimentation.
This is one of the major reasons HTTP 2 is only supported via TLS and only via a complex upgrade protocol.
It's not that you can just do "GET / HTTP/2.0" or something like that.
The TLS part is interesting, as wrapping a protocol into an encrypted channel solves a lot of these issues (but it can break again if you have stupid man in the middle boxes). It just doesn't solve the issue for TLS itself.
The main difference is that a "side channel" of the TLS connection (the NPN or ALPN extensions) is used to negotiate HTTP/2. The upgrade to version 2 without the TLS wrapper failed; so many servers and/or middleboxes had issues with it, that all browser makers decided "HTTP/2 is going to be TLS only" (the current "encrypt all the things" push played a small part, but the main reason was the compatibility problems).
If the newest version of a secure communication protocol includes some way to negotiate down to an older version, that opens the door to downgrade attacks - you risk ending up with a protocol that, in practice, has all the vulnerabilities of both versions.
You can work around this by having downgrade protection, and TLS 1.3 has this out of the box, it was also added belatedly to TLS 1.2 (but obviously the problem there is, you can still downgrade whenever either client or server knows TLS 1.2 but doesn't have protection yet)
In TLS 1.3 the downgrade protection works like this:
If I'm a TLS 1.3 server, and a connection arrives that says it can only handle TLS 1.2 or lower, I scribble the letters "DOWNGRD" (in ASCII) near the end of a field labelled Random that is normally entirely full of random bytes.
If I'm a TLS 1.3 client, I try to ask for TLS 1.3 from the server when I connect, if instead I get a TLS 1.2 or earlier reply, I check the Random field, and see if it spells out "DOWNGRD" near the end. If it does, somebody is trying to downgrade my connection, I am being attacked and can't continue.
This trick works because if bad guys tamper with the Random field then the connection mysteriously fails (client and server are relying on both knowing all these bytes to choose their encryption keys with ephemeral mode) while older clients won't see any meaning in the letters DOWNGRD near the end of these random bytes - so they won't freak out.
You might worry: What if somebody just randomly picked "DOWNGRD" by accident for a TLS 1.3 connection ? If every single person in the world makes one connection per second, this is likely to happen to one person, somewhere, only once every few years. So we don't worry about this.