Even with the 3-phase commit, almost every production MQTT broker sacrifices the "exactly once" requirement to achieve reasonable performance.
MQTT 5 standardizes this by adding a message expiry interval field, though even there it's opt-in by the publisher and defaults to forever.