Brute force attacks run with heavily automated scripts. These scripts focus on regular installations; most of them cannot handle changes to the normal login process (example).
You cannot stop requests to the login page, but you can change the way the login process works, so the script has to take your specific situation into account. Almost all scripts fail here.
An example:
On wpkrauts.com, I am running a custom plugin to log suspicious behavior. It has a built-in login tracker, and it can block IP addresses temporary or permanently.
The plugin has still some UI issues, so I haven’t released it to the public. 🙂
On June 4, I installed another plugin that requires a clicked checkbox. The checkbox is inserted with JavaScript, and its name depends on the site:
if ( defined( 'LOGGED_IN_SALT' ) )
$salt = LOGGED_IN_SALT;
else
$salt = filemtime( __FILE__ );
$this->unique = md5( $_SERVER[ 'HTTP_HOST' ] . $salt );
The first plugin hasn’t blocked a single IP since this day, because no script could parse the very simple JavaScript. The idea here is: Even if the attacking script guesses the password correctly it will never know.
Brute force attacks rely on standard installations. Change the standard, and the attack will probably fail.
A note about Limit Login Attempts: This plugin stores all logged IP addresses in a single option that has to be de/serialized. This list can be quite long after a while, including ten thousands of addresses. I wouldn’t use that.
A more efficient way is looking up just this one IP address from a separate table.
Related: Increase of failed login attempts, brute force attacks?