I implemented the deploy system at my company with Octopus and most of your concerns are shared with us.
With respect to the first point, we do exactly that. We have defined a CI, QA, Pre-Production and created three separate production deployments: Production Alpha, Production Beta and Full Production. Alpha and beta contain distinct subsets of full production.
When it comes to segregating projects to different physical servers, we implemented multiple roles. We've moved away from tagging machines as being "IIS" or "SQL Server", as it sounds like you have. Our roles are more granular and describe specific functionality that the machine provides.
For example, one of our database servers may be tagged "DB-Sales-Reports" and another could be tagged "DB-Sales-Engine". Functionally, this is identical to what you propose but we impose some semantic meaning on what a tag means.
Ideally, what I would like to see is support for allowing a deploy step to target a machine that fulfills "all of the M roles the deploy step targets" I have it tagged with, rather than the current behavior of "any of the M roles the deploy step targets"