Removing a node from an Elasticsearch cluster moves shard copies away from a host before it leaves the data and coordination paths. The maintenance is common during host retirement, capacity reduction, and replacement work where search and indexing should continue while one node disappears.
For self-managed clusters, the standard data-node path is a temporary cluster allocation exclusion. The cluster keeps running while the allocator places shards on remaining nodes; master-eligible removals may also need a voting configuration exclusion when quorum would otherwise be lost.
Use an authenticated HTTPS endpoint that reaches a remaining node, and substitute the departing node's real node.name everywhere node-03 appears. Clear every temporary exclusion after the node is offline so later allocation and voting decisions are not constrained.
Steps to remove a node from an Elasticsearch cluster:
- List the cluster nodes and note the exact node.name to remove.
$ curl --silent --show-error --user "elastic:$ELASTIC_PASSWORD" "https://node-01:9200/_cat/nodes?v&h=ip,name,node.role,master" ip name node.role master 192.0.2.41 node-02 cdfhilmrstw * 192.0.2.43 node-03 cdfhilmrstw - 192.0.2.40 node-01 cdfhilmrstw -
Add --cacert /etc/elasticsearch/certs/http_ca.crt when the cluster CA is not in the host trust store. Use plain http only for clusters that are intentionally unsecured.
- Check cluster health before changing allocation.
$ curl --silent --show-error --user "elastic:$ELASTIC_PASSWORD" "https://node-01:9200/_cluster/health?filter_path=cluster_name,status,timed_out,number_of_nodes,number_of_data_nodes,relocating_shards,initializing_shards,unassigned_shards,number_of_pending_tasks,active_shards_percent_as_number&pretty" { "cluster_name" : "search-cluster", "status" : "green", "timed_out" : false, "number_of_nodes" : 3, "number_of_data_nodes" : 3, "relocating_shards" : 0, "initializing_shards" : 0, "unassigned_shards" : 0, "number_of_pending_tasks" : 0, "active_shards_percent_as_number" : 100.0 }Delay the removal if status is red, if primary shards are unassigned, or if cluster-state tasks are still backing up.
- Add a voting configuration exclusion only when this removal takes half or more of the master-eligible nodes out of service in a short period.
$ curl --silent --show-error --include --user "elastic:$ELASTIC_PASSWORD" --request POST "https://node-01: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
Skip this step for master-ineligible nodes and for routine one-at-a-time removals that leave more than half of the voting configuration online.
Related: How to set Elasticsearch voting configuration exclusions - Exclude the departing data node from shard allocation.
$ curl --silent --show-error --user "elastic:$ELASTIC_PASSWORD" --header "Content-Type: application/json" --request PUT "https://node-01:9200/_cluster/settings" --data '{ "persistent": { "cluster.routing.allocation.exclude._name": "node-03" } }' { "acknowledged" : true, "persistent" : { "cluster" : { "routing" : { "allocation" : { "exclude" : { "_name" : "node-03" } } } } }, "transient" : { } }Use cluster.routing.allocation.exclude._id or cluster.routing.allocation.exclude._ip when a persistent node ID or IP address is safer than node.name. Dedicated master-only and coordinating-only nodes that hold no shards can skip the allocation exclusion.
- Wait for shard relocation to finish before stopping the data node.
$ curl --silent --show-error --user "elastic:$ELASTIC_PASSWORD" "https://node-01:9200/_cluster/health?wait_for_no_relocating_shards=true&timeout=30m&filter_path=cluster_name,status,timed_out,number_of_nodes,number_of_data_nodes,relocating_shards,initializing_shards,unassigned_shards,active_shards_percent_as_number&pretty" { "cluster_name" : "search-cluster", "status" : "green", "timed_out" : false, "number_of_nodes" : 3, "number_of_data_nodes" : 3, "relocating_shards" : 0, "initializing_shards" : 0, "unassigned_shards" : 0, "active_shards_percent_as_number" : 100.0 }Increase timeout for large nodes, slow disks, or clusters with throttled recovery. Investigate allocation rules and free capacity if the request times out.
- Confirm the excluded node now hosts zero shards.
$ curl -sS -u "elastic:$ELASTIC_PASSWORD" "https://node-01:9200/_cat/allocation/node-03?v&h=shards,node" shards node 0 node-03
Do not stop a data node that still shows shard copies unless the maintenance plan accepts the recovery and availability impact.
- Stop the Elasticsearch service on the departing host.
$ sudo systemctl stop elasticsearch.service
Run this on the node being removed, not on the node used for the cluster API checks.
- Disable automatic startup on the decommissioned host.
$ sudo systemctl disable elasticsearch.service Removed "/etc/systemd/system/multi-user.target.wants/elasticsearch.service".
Skip this step when the node is being stopped only for a temporary repair and must rejoin with the same identity.
- Verify the node is no longer listed after the service stops.
$ curl --silent --show-error --user "elastic:$ELASTIC_PASSWORD" "https://node-01:9200/_cat/nodes?v&h=ip,name,node.role,master" ip name node.role master 192.0.2.41 node-02 cdfhilmrstw * 192.0.2.40 node-01 cdfhilmrstw -
- Clear the temporary allocation exclusion.
$ curl --silent --show-error --user "elastic:$ELASTIC_PASSWORD" --header "Content-Type: application/json" --request PUT "https://node-01:9200/_cluster/settings" --data '{ "persistent": { "cluster.routing.allocation.exclude._name": null } }' { "acknowledged" : true, "persistent" : { }, "transient" : { } }Clearing the exclusion prevents it from blocking a replacement node that reuses the same node.name or address.
- Clear the voting configuration exclusion if one was added earlier.
$ curl --silent --show-error --include --user "elastic:$ELASTIC_PASSWORD" --request DELETE "https://node-01: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
Clusters should normally have an empty voting configuration exclusion list after maintenance ends.
- Verify cluster health after the removal.
$ curl --silent --show-error --user "elastic:$ELASTIC_PASSWORD" "https://node-01:9200/_cluster/health?filter_path=cluster_name,status,timed_out,number_of_nodes,number_of_data_nodes,relocating_shards,initializing_shards,unassigned_shards,number_of_pending_tasks,active_shards_percent_as_number&pretty" { "cluster_name" : "search-cluster", "status" : "green", "timed_out" : false, "number_of_nodes" : 2, "number_of_data_nodes" : 2, "relocating_shards" : 0, "initializing_shards" : 0, "unassigned_shards" : 0, "number_of_pending_tasks" : 0, "active_shards_percent_as_number" : 100.0 }
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.