Removing master-eligible nodes without adjusting cluster coordination can strand an Elasticsearch cluster without enough votes to publish cluster-state changes or elect a master. Voting configuration exclusions are the manual safety control for maintenance windows where automatic shrink is not enough, such as shrinking the voting set below three nodes or taking half or more of the master-eligible nodes out of service in a short period.
Elasticsearch stores the current voting configuration in cluster metadata and updates it through the /_cluster/voting_config_exclusions API. When a POST request returns 200 OK, current Elastic docs guarantee that the specified node has been removed from the voting configuration and will not rejoin it until the exclusions are cleared.
Recent self-managed package installs usually expose HTTPS and authentication by default, so the curl examples may need https://, --cacert, and credentials instead of plain http. This API applies only to master-eligible nodes, the exclusion list persists until it is cleared, and the list is capped by cluster.max_voting_config_exclusions which defaults to 10, so clean up exclusions after the node is removed or when the maintenance window ends.
$ curl -sS "http://localhost:9200/_cluster/health?filter_path=cluster_name,status,number_of_nodes,number_of_data_nodes,number_of_pending_tasks&pretty"
{
"cluster_name" : "search-cluster",
"status" : "green",
"number_of_nodes" : 3,
"number_of_data_nodes" : 3,
"number_of_pending_tasks" : 0
}
Delay the maintenance if status is red, if a master is not elected, or if cluster-state tasks are still backing up.
$ curl -sS "http://localhost:9200/_cat/nodes?v&h=id,ip,node.role,master,name" id ip node.role master name EsJ3 192.0.2.41 cdfhilmrstw * node-01 bPfA 192.0.2.42 cdfhilmrstw - node-02 5LCz 192.0.2.43 cdfhilmrstw - node-03
The compact node.role string contains m on master-eligible nodes. On clusters with more than three master-eligible nodes, removing fewer than half of them at once usually does not require this API because the voting configuration shrinks automatically.
Use node_ids instead of node_names when the node name can change but the persistent ID is known.
$ curl -sS "http://localhost:9200/_cluster/state?filter_path=metadata.cluster_coordination.voting_config_exclusions&pretty"
{
"metadata" : {
"cluster_coordination" : {
"voting_config_exclusions" : [ ]
}
}
}
Clusters should normally keep this list empty. The limit comes from cluster.max_voting_config_exclusions, which defaults to 10.
$ curl -sS -D - -o /dev/null -X POST "http://localhost:9200/_cluster/voting_config_exclusions?node_names=node-03&timeout=1m" HTTP/1.1 200 OK X-elastic-product: Elasticsearch content-type: text/plain; charset=UTF-8 content-length: 0
Current Elastic docs state that an HTTP 200 OK response guarantees the node has been removed from the voting configuration. If the request times out or returns a different status, retry or resolve the cluster issue before stopping the node.
$ curl -sS "http://localhost:9200/_cluster/state?filter_path=metadata.cluster_coordination.voting_config_exclusions&pretty"
{
"metadata" : {
"cluster_coordination" : {
"voting_config_exclusions" : [
{
"node_id" : "5LCzbbBUQsiIapX4IBIfBw",
"node_name" : "node-03"
}
]
}
}
}
The API also accepts comma-separated values so multiple nodes can be excluded together when the maintenance plan requires it.
$ sudo systemctl stop elasticsearch
Do not stop the node before the exclusion request returns 200 OK, and do not take down too many remaining master-eligible nodes or the cluster can lose quorum.
$ curl -sS "http://localhost:9200/_cat/master?v" id host ip node EsJ3x_b5Rjipi5HB219Rbg 192.0.2.41 192.0.2.41 node-01
A populated row confirms that the remaining voters still elected a master after the excluded node left.
$ curl -sS "http://localhost:9200/_cluster/health?filter_path=cluster_name,status,number_of_nodes&pretty"
{
"cluster_name" : "search-cluster",
"status" : "green",
"number_of_nodes" : 2
}
$ curl -sS -D - -o /dev/null -X DELETE "http://localhost:9200/_cluster/voting_config_exclusions?wait_for_removal=true" HTTP/1.1 200 OK X-elastic-product: Elasticsearch content-type: text/plain; charset=UTF-8 content-length: 0
wait_for_removal=true is the default and is the safer choice for permanent removal. Use wait_for_removal=false only when the node is expected to return or the exclusion was added in error.
$ curl -sS "http://localhost:9200/_cluster/state?filter_path=metadata.cluster_coordination.voting_config_exclusions&pretty"
{
"metadata" : {
"cluster_coordination" : {
"voting_config_exclusions" : [ ]
}
}
}