AWS schedules events on EC2 instances when the underlying host needs maintenance or is degraded. If nobody acts, the instance is rebooted, stopped or retired at a time AWS chooses, and that time is often in your business hours. This checklist finds the events, picks the right action for each and makes sure the next notice reaches an owner.
Event types and what they do
| Event code | What happens | Your options |
|---|---|---|
instance-reboot | The instance is rebooted | Reboot it yourself in a window, or reschedule |
system-reboot | The host is rebooted, which also restarts the instance | Reschedule if a deadline is shown; you can't complete it yourself with a reboot |
system-maintenance | Network or power maintenance on the host; the instance may lose connectivity briefly | Usually none; plan for a short blip |
instance-stop | The instance is stopped | Stop and start it yourself before the date |
instance-retirement | The instance is stopped (EBS-backed) or terminated (instance store-backed) | Stop and start (EBS-backed), or replace the instance |
Completed events keep appearing for a while. Their description begins with [Completed] (or [Canceled]), so filter those out.
1. Find every open event
Scheduled events are listed per Region. This loop checks every Region enabled in the account:
for r in $(aws ec2 describe-regions --query "Regions[].RegionName" --output text); do
echo "== $r"
aws ec2 describe-instance-status --region "$r" --include-all-instances \
--filters Name=event.code,Values=instance-reboot,system-reboot,system-maintenance,instance-stop,instance-retirement \
--query "InstanceStatuses[].{id:InstanceId,az:AvailabilityZone,code:Events[0].Code,desc:Events[0].Description,notBefore:Events[0].NotBefore,deadline:Events[0].NotBeforeDeadline}" \
--output text | grep -v -e '\[Completed\]' -e '\[Canceled\]'
done
If your organisation uses AWS Health organisational view, you can list scheduled EC2 changes for all accounts from the management or delegated admin account. The AWS Health global endpoint is in us-east-1:
aws health describe-events-for-organization --region us-east-1 \
--filter services=EC2,eventTypeCategories=scheduledChange,eventStatusCodes=upcoming \
--query "events[].{type:eventTypeCode,region:region,start:startTime,arn:arn}" --output table
Each event type code (for example, the instance retirement types) is listed in the output. Names vary over time, so match on the scheduledChange category instead of hardcoding codes.
- Every Region checked, including Regions nobody "uses"
- Each instance mapped to an owner and a service (use the
Name,OwnerorApplicationtags)
aws ec2 describe-instances --instance-ids i-0abc123def4567890 \
--query "Reservations[].Instances[].{type:InstanceType,root:RootDeviceType,lifecycle:InstanceLifecycle,asg:Tags[?Key=='aws:autoscaling:groupName']|[0].Value,name:Tags[?Key=='Name']|[0].Value}" \
--output table
2. Decide the action per instance
- Part of an Auto Scaling group? Terminate the instance in a quiet period and let the group replace it. Use
aws autoscaling terminate-instance-in-auto-scaling-group --instance-id <id> --no-should-decrement-desired-capacity. - EBS-backed standalone instance with a retirement or stop event? Stop and start it in your window. A stop and start moves it to a healthy host and clears the event. A reboot doesn't.
- Instance store-backed, or has instance store volumes with data? Copy the data off first. Retirement terminates instance store-backed instances, and a stop wipes instance store volumes.
- Reboot event with a deadline? Reschedule it into your maintenance window (see step 3), or reboot yourself for
instance-reboot. - Clustered workload (database primary, AD domain controller, broker)? Fail over or move the role off the instance first.
Caution
A stop and start can change things the application depends on. The public IPv4 address changes unless the instance has an Elastic IP, instance store volumes are wiped, and the instance can fail to start if its type has no capacity in the AZ. Check for an Elastic IP and instance store before you stop it, and have a rollback plan, such as an AMI or recent snapshot.
Check for instance store and Elastic IP before stopping:
ID=i-0abc123def4567890
aws ec2 describe-instances --instance-ids $ID \
--query "Reservations[].Instances[].{publicIp:PublicIpAddress,blockDevices:BlockDeviceMappings[].DeviceName}" --output json
aws ec2 describe-addresses --filters Name=instance-id,Values=$ID --query "Addresses[].PublicIp"
Run the stop and start in the window:
aws ec2 stop-instances --instance-ids $ID && aws ec2 wait instance-stopped --instance-ids $ID
aws ec2 start-instances --instance-ids $ID && aws ec2 wait instance-status-ok --instance-ids $ID
3. Reschedule when the window is wrong
Only events that show a deadline (NotBeforeDeadline) can be rescheduled. The new time must be before the deadline and at least 60 minutes from now. Events that start within the next few minutes can't be changed.
EVENT=$(aws ec2 describe-instance-status --instance-ids $ID --include-all-instances \
--query "InstanceStatuses[0].Events[0].InstanceEventId" --output text)
aws ec2 modify-instance-event-start-time --instance-id $ID \
--instance-event-id "$EVENT" --not-before 2026-11-08T02:00:00Z
- New time is inside an agreed maintenance window
- Change recorded in your change calendar with the instance owner
Tip
To stop picking times one event at a time, create an event window. AWS then schedules eligible events inside it. The window doesn't cover every event type (for example, expedited and network maintenance events), so check the EC2 documentation for current coverage.
aws ec2 create-instance-event-window --name sun-0200-0600 \ --time-range StartWeekDay=sunday,StartHour=2,EndWeekDay=sunday,EndHour=6 aws ec2 associate-instance-event-window --instance-event-window-id iew-0abc123def4567890 \ --association-target InstanceIds=i-0abc123def4567890
4. Verify after the event
- The event no longer appears in the list from step 1, or it shows
[Completed] - Both status checks pass:
aws ec2 describe-instance-status --instance-ids $ID --query "InstanceStatuses[].[SystemStatus.Status,InstanceStatus.Status]" - The application health check is green behind its load balancer
- DNS records and allowlists are updated if the public IP changed
- Data volumes mounted correctly. Check
/etc/fstabuses UUIDs andnofail, not NVMe device names.
You can check the service from the instance without SSH by using Systems Manager:
aws ssm send-command --instance-ids $ID --document-name AWS-RunShellScript \
--parameters 'commands=["uptime","systemctl --failed","df -h"]' \
--query "Command.CommandId" --output text
5. Route future notices to an owner
An EventBridge rule on AWS Health catches scheduled changes as soon as AWS announces them:
aws events put-rule --name ec2-scheduled-changes \
--event-pattern '{"source":["aws.health"],"detail-type":["AWS Health Event"],"detail":{"service":["EC2"],"eventTypeCategory":["scheduledChange"]}}'
aws events put-targets --rule ec2-scheduled-changes \
--targets Id=ops,Arn=arn:aws:sns:eu-west-1:111122223333:ops-maintenance
AWS Health events are delivered in the Region the event applies to, so create the rule in every Region you run instances in. The SNS topic policy must also allow events.amazonaws.com to publish.
Prevent it next time
- Put stateless instances in Auto Scaling groups so a retirement just means a replacement.
- Use Elastic IPs or DNS names, not raw public IPs, for anything another party allowlists.
- Avoid relying on instance store for data you need to keep.
- Attach an event window to every standalone production instance.
- Keep the EventBridge rule and an owner tag on every instance, so each notice reaches a named person and doesn't sit in the root account's inbox.
- Turn on CloudWatch auto recovery (
StatusCheckFailed_Systemwith therecoveraction) for standalone EBS-backed instances that support it.