We try to make sure all changes to a message contract are both forward and backward compatible. In those rare cases where there is truly a breaking change in the message contract, we consider that a different message (a new kind of message).
We use the Parallel Change pattern to manage such breaking changes.
In cases where we have control over the downstream consumers, we make sure that they are ready to consume the new kind of message before it starts being published. It will also retain it's ability to consume the old kind of message so it can drain the queue of any existing messages. Depending on your messaging platform you may or may not need to use two queues.
In cases where we don't have direct control over the downstream consumers, we publish both the old and new messages in parallel. This gives the downstream consumers a grace period where they can migrate away from the old messages in favour of the new ones. We flag the old messages as deprecated during this period. After the grace period, we simply stop publishing the old messages.