Sort refusals into three kinds and fix the wording of each. A public endpoint refuses things all day, and every refusal teaches the caller something. The question is what you are willing to teach.
- Hostile - a fetch, an attach, an engine setting, a write on a read-only surface. One short generic sentence and nothing else, byte-identical at every layer. If the edge says one thing and the backend says another, a prober learns which layer caught them and what is worth encoding past.
- Capability - a function or feature you simply do not permit. Refuse and name the category, never the token you matched. An analyst deserves to know why; a prober should not be able to map your list one word at a time.
- Limit - rows, response size, time. Name the limit and the value, because this is the only one the caller can actually act on.
For functions, keep a positive list. A blocklist allows every function you did not think of, and engines add functions every release, so a blocklist is out of date the day it ships. A positive list refuses anything new until you admit it, which is what catches the ones nobody predicted.
Keep the lists in one file and compile both layers from it. Two hand-typed copies drift in the first week. Put the bands and the allowed functions in one version-controlled file, compile the edge and the backend from it, and check the deployed copies against that file on a schedule.
Whether a refusal also BLOCKS the caller is a separate decision from the wording, and worth keeping separate. Blocking on a single refused query jails broken clients and researchers along with attackers. Refuse every time, and block on something stronger: bait contact, a forged identity, repeated distinct hostile attempts.
Never print a consequence you cannot deliver. "Sustained attempts are treated as abuse" states a position and removes the did-not-know defence. "You will be banned" is a promise that anyone rotating addresses disproves in a minute, and the first person to test it learns you cannot follow through, which discredits every other line on the page.
The general error-message rule - log the detail, return what the caller can act on - is here. Full checklist item: the SQL and query-surface section.
Building something like this? How I work covers the rates, the availability and what I take on.