Clock recovery using Mueller and Muller adds noise affecting EVM or SNR (Two cases - GNU Radio & Python code)
Unlike the Gardner Loop, the M&amp;M synchronizer should be performed after the RRC filter in the receiver for best performance.  With cases of high RRC alpha, the M&amp;M won't work as expected without the complete Raised-Cosine filtering (RRC in transmitter followed by RRC in receiver) as the slope of the error term will reverse, with high self-noise, as I demonstrate in this plot below:

The blue line is the discriminator output showing average error versus offset, and the red line is the standard deviation of that error showing the self-noise. In the first case the slope of error output versus offset actually inverts in proximity of the lock point (so it would work, barely, if the feedback is inverted but with very high self-noise and low slope so very low timing SNR otherwise it would lock interestingly at 1/4 sample offset).
Specific to the OP's case, below is the same chart with a lower (and typical) RRC alpha where the discriminator curve is quite similar but the self-noise is much higher at the lock condition if the M&amp;M is used prior to the second RRC filter.

Both the Gardner Loop and M&amp;M will have self noise, but the self noise is typically averaged out in the recovery loop to be well below the receiver noise floor once the accumulated time sample location is determined for each new sample.
Why the difference between Gardner and M&amp;M?
It is interesting that the Gardner performs better using the samples prior to the second RRC filter while the M&amp;M synchronizer is better after. This is because the M&amp;M synchronizer operates on one sample per symbol using sample locations at the decision locations and thus depends on the slope of the waveform in vicinity of these locations to determine timing error. The Gardner operates using 2 samples per symbol and operates by approximating the slope at the zero crossings, which have less timing jitter before the second RRC filter as we see in the eye diagrams below (notice the wider range of zero-crossing transition times in the waveform after the second RRC filter):

Generally for timing detection our best estimates should be obtained from the zero crossings where the slope and therefore sensitivity to timing error would be highest. This is true on average and is one of the reasons the Gardner Loop has better SNR performance in low SNR conditions (and M&amp;M has better performance in high SNR conditions since it uses decisions in its computation, which eliminate noise if the decisions are correct). However, the competing requirement of having no inter-symbol interference at the data decision location results in increased zero-crossing jitter at the waveform locations of interest for timing detection. One solution to this if self-noise was an issue (it typically isn't as the timing loop bandwidth is so much smaller as to average it out) is the use of pre-filters which can equalize the ISI at the zero crossing locations for timing detection, on a separate data-path from the data which has zero ISI at the symbol detection locations as desired for best data-recovery performance.