I'm sure your first response is similar to my initial answer; add the attribute, onclick="this.disabled = true;" to the button. Unfortunately, this can't be applied to a server-side button because it also disables any postback events.
As a workaround, I added a duplicate HTML button to the page. It is important that the server-side button has an extra attribute; style="display: none;". This prevents it from being rendered to the browser but will still exist in the source code. You may be thinking that Visible="false" would do the same but this prevents the control from creating any output at all. The HTML button is the visible replacement but when clicked, it will trigger the click event of the server-side button or "Ghost Button".
<input type="button" onclick="this.disabled = true; btnTest.click" value="Test">
<asp:Button ID="btnTest" runat="server" style="display: none" />