Use Replace[] instead of ReplaceAll[] on the individual matrix entries:
M = {{s \[Beta]/(c + a), 0}, {0, s \[Beta]/(b + a)}}; F = {{\[Beta], x \[Beta]}, {-2 \[Beta], -3 \[Beta]}}; M == Replace[M, _?Negative -> 0, {2}] (* Succeeds *) M == Replace[M, _?Internal`SyntacticNegativeQ -> 0, {2}](* Succeeds *) M == Replace[M, x_ /; x < 0 -> 0, {2}] (* Succeeds *) M == Replace[M, _. _?Negative -> 0, {2}] (* Succeeds *) Replace[F, _?Negative -> 0, {2}] (* FAILS *) Replace[F, _?Internal`SyntacticNegativeQ -> 0, {2}] (* Succeeds *) Replace[F, x_ /; x < 0 -> 0, {2}] (* FAILS *) Replace[F, _. _?Negative -> 0, {2}] (* Succeeds *) Restricting the level at which the rules are applied causes some of them to fail. I included them to show that Replace[mat, rule, {2}] does not work for every rule.
(The OP's M is an odd example in that no change is supposed to occur. Both good rules and bad rules might succeed at doing nothing for both good and bad reasons.)