If they're separate products, they should probably just get their own versions. In your examples, you could say "Hey customer 1, you have M1 v3.4 and M5 v3.4" and "Hey customer 2, you have M1 v3.4 and M3 v3.3 -- you should probably update M3 to latest".
For simplicity, you might want to keep them all roughly the same, but that would be more of a cosmetic decision. The main thing is the version should identify the source code it came from, and should be unique. Some services just use a combination of the auto-incrementing build number and/or git commit hash, so they can just say something like "M1 #fe45ce2 build 12043".
Why version?
Knowing why version numbers are important helps to figure out what they need to be. Commonly:
- Be able to communicate what's running (between customer/dev/PM/support/etc)
- Be able to tell if there's an update or not (and how far behind you are)
- Know if a newly discovered bug is really new or already known/fixed
- Figure out what revision of code (and/or build) a piece of running software is from
Dependencies
Here's one of the things with microservices vs monoliths: each microservice is effectively its own, independent product. If they are talking to each other, you now have to think about version cross-compatibility (forwards and backwards) between all the independent services.
Does M1 v3.4 work with M3 v3.3? Does M3 v3.5 work with M1 v3.1?
You don't have to be forwards- or backwards-compatible (and certainly not for all versions) but then you introduce other operational challenges, like if someone updates M1 then they have to update M3 and until they do, one or both services will be broken -- and you probably want to think about how you present "broken" to end users (eg: do they see an HTTP 500 error page with a stack trace or an "under maintenance" page?).
Single version number
If you have a single repository and a single build that contains all your services, it's pretty easy to version that in a consistent way (whatever you choose). You still have to figure out how you handle dependencies and cross-compatibility, so long as it's possible to install/upgrade independently.
If you have independent repositories, but a single build, you can use a build number. If you have a single repository but independent builds, you can use a source code revision.
If everything is independent, there's really no way to enforce consistency -- it would have to be manual and pretty easy to mess it up (which means it will eventually be messed up).
If you really want a consistent version, have everything in one repository/build, and want customers to be only on one version so you don't have to worry about cross-compatibility, then microservices might not be the right architecture choice for your situation, so you'll need to reconsider what you're trying to achieve and what trade-offs you want to compromise on.