---
title: "AWS EC2 Instance Management with Boto3: Start, Stop, and Query Instances"
lang: "en"
author: "Mohammad Abu Mattar"
canonical: https://mkabumattar.com/post/aws-ec2-instance-management-boto3-python
---

![Blog post image for AWS EC2 Instance Management with Boto3: Start, Stop, and Query Instances - Learn how to automate AWS EC2 instance management using Python and Boto3. This guide covers authentication with IAM roles, starting and stopping instances, using waiters, filtering by tags, running bulk operations, and handling API errors. Practical code examples included for DevOps engineers and cloud developers](/_astro/hero.PnHlvJay_Z1DLqhV.webp)

[Home](/)›[Codesnippets](/codesnippets)›[All Categories](/codesnippets/categories)›[Cloud](/codesnippets/categories/cloud)

Codesnippets

[Cloud](/codesnippets/categories/cloud)[Aws](/codesnippets/categories/aws)[Devops](/codesnippets/categories/devops)[Automation](/codesnippets/categories/automation)[Python](/codesnippets/python)

# AWS EC2 Instance Management with Boto3: Start, Stop, and Query Instances

[Mohammad Abu Mattar](/authors/mohammad-abu-mattar)Published: 14 Apr 202610 Mins read12 Mins listen

[Markdown for AI(opens in a new tab)](/post/aws-ec2-instance-management-boto3-python/index.md "Open the plain-Markdown version of this page, for pasting into an AI tool")

TL;DR

Learn how to automate AWS EC2 instance management using Python and Boto3. This guide covers authentication with IAM roles, starting and stopping instances, using waiters, filtering by tags, running bulk operations, and handling API errors. Practical code examples included for DevOps engineers and cloud developers

Series

[AWS Automation](/series/aws-automation)4/4

[PreviousList S3 Buckets](/codesnippets/post/python-list-s3-buckets)

All posts in this series (4)

Code Snippets4

1.  [Check S3 Bucket Existence](/codesnippets/post/bash-s3-bucket-exists)
2.  [AWS Secrets Manager](/codesnippets/post/nodejs-aws-secrets-manager)
3.  [List S3 Buckets](/codesnippets/post/python-list-s3-buckets)
4.  [AWS EC2 Instance Management with Boto3: Start, Stop, and Query InstancesYou are here](/codesnippets/post/aws-ec2-instance-management-boto3-python)

### AWS EC2 Instance Management with Boto3: Start, Stop, and Query Instances

Contents

[Why automate EC2 management with Boto3?](#why-automate-ec2-management-with-boto3)[Setting up Boto3 and authenticating with AWS](#setting-up-boto3-and-authenticating-with-aws)[Option 1: IAM roles (best for EC2 and Lambda)](#option-1-iam-roles-best-for-ec2-and-lambda)[Option 2: named profiles (best for local development)](#option-2-named-profiles-best-for-local-development)[Starting and stopping EC2 instances](#starting-and-stopping-ec2-instances)[Stopping an instance](#stopping-an-instance)[Starting an instance](#starting-an-instance)[Using Boto3 waiters to block until a state is reached](#using-boto3-waiters-to-block-until-a-state-is-reached)[Filtering and querying instances](#filtering-and-querying-instances)[Querying by state](#querying-by-state)[Querying by tags](#querying-by-tags)[Bulk operations: stopping instances by tag or VPC](#bulk-operations-stopping-instances-by-tag-or-vpc)[Stop all instances in a VPC](#stop-all-instances-in-a-vpc)[Stop all instances with a specific tag](#stop-all-instances-with-a-specific-tag)[Error handling: throttling, permissions, and invalid states](#error-handling-throttling-permissions-and-invalid-states)[Frequently asked questions](#frequently-asked-questions)[References](#references)

If you’ve ever spent 20 minutes clicking through the AWS Console just to stop a handful of dev instances, you already know the pain. It’s tedious, it doesn’t scale, and one wrong click can ruin your afternoon.

That’s where Boto3 comes in. It’s the official AWS SDK for Python, and it lets you talk to AWS services, including EC2, directly from your code. Instead of pointing and clicking, you write a script once and run it whenever you need it. Your code doesn’t get tired, doesn’t misclick, and works the same at 3 AM as it does at 3 PM.

This guide covers everything you need to get comfortable with EC2 automation: setting up authentication, starting and stopping instances, waiting for state changes, filtering by tags, running bulk operations, and handling errors.

* * *

## [Why automate EC2 management with Boto3?](#why-automate-ec2-management-with-boto3)

_Why bother writing code when the AWS Console already does the job?_

Fair question. The console is fine when you’ve got two or three instances. But once you’re managing a real environment, manual work starts costing you more than time.

Every action you take through the console depends on a human doing it right, every single time. With Boto3, you write the logic once, and it runs consistently regardless of who’s on call or how tired they are.

Here’s where automation pays off most:

-   **Scheduled shutdowns:** Stop dev and staging instances overnight or on weekends. There’s no reason to pay for servers that nobody’s using at 2 AM.
-   **Consistent tagging:** Every instance your script touches gets tagged correctly. No more missing `Environment` or `Owner` tags because someone forgot.
-   **Incident response:** When something goes wrong, your runbook can stop a compromised instance or spin up a replacement without waiting for a human to log in.
-   **Audit trails:** Log every action with timestamps, so you’ve got a clear record of what happened, when, and why.
-   **Fewer mistakes:** Repetitive manual work breeds errors. Scripts don’t forget steps or click the wrong button.

Once your automation is in place, managing 200 instances takes roughly the same effort as managing two.

* * *

## [Setting up Boto3 and authenticating with AWS](#setting-up-boto3-and-authenticating-with-aws)

_How do you connect Boto3 to your AWS account securely?_

Start with the install:

Terminal window

```
pip install boto3
```

Now, authentication. This is where a lot of people make mistakes, so it’s worth doing right from the start. The method you use should depend on where your code runs.

### [Option 1: IAM roles (best for EC2 and Lambda)](#option-1-iam-roles-best-for-ec2-and-lambda)

If your script runs on an EC2 instance or a Lambda function, attach an IAM role to that resource. Boto3 picks up the credentials automatically from the instance metadata service. You don’t need to touch a key file or set any environment variables.

```
1import boto32
3# No keys needed here Boto3 reads the IAM role attached to this instance4ec2_client = boto3.client('ec2', region_name='us-east-1')5
6# Quick check to confirm the connection works7response = ec2_client.describe_instances()8print('Connected via IAM role good to go.')
```

This is the cleanest approach for production. There are no credentials to rotate, leak, or accidentally commit to Git.

### [Option 2: named profiles (best for local development)](#option-2-named-profiles-best-for-local-development)

When you’re working locally, use a named AWS CLI profile. It keeps credentials in `~/.aws/credentials` where they belong, not in your source code.

Terminal window

```
# Run this once in your terminal to set up a profileaws configure --profile myproject
```

```
1import boto32
3# Load credentials from the 'myproject' profile in ~/.aws/credentials4session = boto3.Session(profile_name='myproject')5ec2_client = session.client('ec2', region_name='us-east-1')6
7print(f'Using profile: {session.profile_name}')
```

You can have multiple profiles for different accounts or environments, which makes switching between dev and prod much easier.

> **A word on hardcoded credentials:** Don’t do it. Not in scripts, not in config files checked into source control, not anywhere. Use IAM roles in production and named profiles locally. If you’re using access keys, rotate them regularly and give them only the permissions they actually need.

* * *

## [Starting and stopping EC2 instances](#starting-and-stopping-ec2-instances)

_How do you start and stop instances programmatically with Boto3?_

This is probably why you’re here. Boto3 uses `start_instances` and `stop_instances` for these operations. Both are simple calls, but there are a few details worth knowing.

### [Stopping an instance](#stopping-an-instance)

```
1import boto32from botocore.exceptions import ClientError3
4def stop_instance(instance_id: str, region: str = 'us-east-1') -> dict:5    """Stop a running EC2 instance and return the state transition."""6    ec2 = boto3.client('ec2', region_name=region)7
8    try:9        response = ec2.stop_instances(InstanceIds=[instance_id])10
11        # AWS tells us both the old state and the new state12        state_info = response['StoppingInstances'][0]13        previous = state_info['PreviousState']['Name']14        current = state_info['CurrentState']['Name']15
16        print(f'{instance_id}: {previous} -> {current}')17        return response18
19    except ClientError as e:20        print(f'Could not stop instance: {e.response["Error"]["Code"]} - {e}')21        raise22
23# Usage24stop_instance('i-0abcd1234ef567890')
```

### [Starting an instance](#starting-an-instance)

```
1import boto32from botocore.exceptions import ClientError3
4def start_instance(instance_id: str, region: str = 'us-east-1') -> dict:5    """Start a stopped EC2 instance and return the state transition."""6    ec2 = boto3.client('ec2', region_name=region)7
8    try:9        response = ec2.start_instances(InstanceIds=[instance_id])10
11        state_info = response['StartingInstances'][0]12        previous = state_info['PreviousState']['Name']13        current = state_info['CurrentState']['Name']14
15        print(f'{instance_id}: {previous} -> {current}')16        return response17
18    except ClientError as e:19        code = e.response['Error']['Code']20
21        # Don't crash if the instance is already running22        if code == 'IncorrectInstanceState':23            print(f'{instance_id} is already in the desired state.')24        else:25            raise26
27# Usage28start_instance('i-0abcd1234ef567890')
```

One thing worth noting: both methods accept a list of instance IDs, so you can act on multiple instances in a single API call. If you’re managing more than one instance, that’s a lot cleaner than looping and calling separately.

```
1# Stop multiple instances at once no loop needed2ec2 = boto3.client('ec2', region_name='us-east-1')3ec2.stop_instances(InstanceIds=[4    'i-0abcd1234ef567890',5    'i-0efgh5678ij901234',6    'i-0klmn9012op345678',7])
```

The response tells you the previous and current state for each one, which makes logging and auditing easy.

* * *

## [Using Boto3 waiters to block until a state is reached](#using-boto3-waiters-to-block-until-a-state-is-reached)

_How do you know when an instance has actually finished starting or stopping?_

Here’s a common mistake: you call `start_instances`, assume it’s done, and immediately try to SSH in. But the instance is still booting. Your script fails, and now you’re debugging something that wasn’t actually broken.

The fix is waiters. A Boto3 waiter is a built-in polling loop that keeps checking the AWS API until your instance reaches the state you want. It handles the timing for you and raises an error if something goes wrong or takes too long.

```
1import boto32from botocore.exceptions import WaiterError3
4def start_and_wait(instance_id: str, region: str = 'us-east-1'):5    """Start an instance and block until it's fully running."""6    ec2 = boto3.client('ec2', region_name=region)7
8    ec2.start_instances(InstanceIds=[instance_id])9    print(f'Starting {instance_id}...')10
11    waiter = ec2.get_waiter('instance_running')12
13    try:14        waiter.wait(15            InstanceIds=[instance_id],16            WaiterConfig={17                'Delay': 15,       # Check every 15 seconds18                'MaxAttempts': 40  # Give up after ~10 minutes19            }20        )21        print(f'{instance_id} is running.')22
23    except WaiterError as e:24        print(f'Waiter timed out: {e}')25        raise26
27
28def stop_and_wait(instance_id: str, region: str = 'us-east-1'):29    """Stop an instance and block until it's fully stopped."""30    ec2 = boto3.client('ec2', region_name=region)31
32    ec2.stop_instances(InstanceIds=[instance_id])33    print(f'Stopping {instance_id}...')34
35    waiter = ec2.get_waiter('instance_stopped')36
37    try:38        waiter.wait(39            InstanceIds=[instance_id],40            WaiterConfig={'Delay': 15, 'MaxAttempts': 40}41        )42        print(f'{instance_id} is stopped.')43
44    except WaiterError as e:45        print(f'Waiter failed: {e}')46        raise
```

The four most useful EC2 waiters are `instance_running`, `instance_stopped`, `instance_terminated`, and `instance_exists`. Each one polls `describe_instances` under the hood and checks the state automatically, so you don’t have to.

If you want to wait on multiple instances at once, just pass all the IDs together:

```
1# Wait for several instances to stop one waiter call handles all of them2waiter = ec2.get_waiter('instance_stopped')3waiter.wait(4    InstanceIds=['i-0abc123', 'i-0def456', 'i-0ghi789'],5    WaiterConfig={'Delay': 15, 'MaxAttempts': 40}6)7print('All instances are stopped.')
```

> **Tip:** Tune `Delay` and `MaxAttempts` based on your actual instances. A small instance with a simple AMI might be running in under a minute. A larger one running a heavy bootstrap script could take five or ten. If your waiter times out too often, bump up `MaxAttempts` before adding more complex logic.

* * *

## [Filtering and querying instances](#filtering-and-querying-instances)

_How do you find the right instances without knowing their IDs ahead of time?_

Hardcoding instance IDs is a trap. Instances get replaced, IDs change, and suddenly your script is managing the wrong thing, or nothing at all. A better approach is to query by attributes you control, like tags or state.

### [Querying by state](#querying-by-state)

```
1import boto32
3def get_instances_by_state(state: str, region: str = 'us-east-1') -> list:4    """5    Return all instances in a given state.6    Valid states: 'running', 'stopped', 'pending', 'stopping', 'terminated'7    """8    ec2 = boto3.client('ec2', region_name=region)9
10    response = ec2.describe_instances(11        Filters=[{'Name': 'instance-state-name', 'Values': [state]}]12    )13
14    # describe_instances groups results into Reservations, so we flatten them15    instances = []16    for reservation in response['Reservations']:17        instances.extend(reservation['Instances'])18
19    return instances20
21
22# Find everything that's currently running23running = get_instances_by_state('running')24print(f'{len(running)} running instance(s) found.')25
26for inst in running:27    print(f"  {inst['InstanceId']}  {inst['InstanceType']}  {inst['Placement']['AvailabilityZone']}")
```

### [Querying by tags](#querying-by-tags)

```
1import boto32
3def get_instances_by_tag(tag_key: str, tag_value: str, region: str = 'us-east-1') -> list:4    """Find instances that have a specific tag key/value pair."""5    ec2 = boto3.client('ec2', region_name=region)6
7    # AWS filter syntax for tags is 'tag:<key>'8    response = ec2.describe_instances(9        Filters=[{'Name': f'tag:{tag_key}', 'Values': [tag_value]}]10    )11
12    instances = []13    for reservation in response['Reservations']:14        instances.extend(reservation['Instances'])15
16    return instances17
18
19# Find all production instances20prod = get_instances_by_tag('Environment', 'production')21
22for inst in prod:23    # Pull the Name tag if it exists, otherwise label it 'unnamed'24    name = next(25        (t['Value'] for t in inst.get('Tags', []) if t['Key'] == 'Name'),26        'unnamed'27    )28    print(f"  {inst['InstanceId']}  {name}  {inst['State']['Name']}")
```

You can stack filters together, too. AWS applies them with AND logic, so you’ll only get instances that match all of them:

```
1# Only running instances in the production environment both filters must match2response = ec2.describe_instances(3    Filters=[4        {'Name': 'tag:Environment', 'Values': ['production']},5        {'Name': 'instance-state-name', 'Values': ['running']}6    ]7)
```

That single call replaces what would otherwise be a manual filter in the console or a clunky post-processing loop in code.

* * *

## [Bulk operations: stopping instances by tag or VPC](#bulk-operations-stopping-instances-by-tag-or-vpc)

_How do you stop an entire group of instances at once without listing each ID manually?_

This is where scripting really earns its keep. Instead of hunting down individual instance IDs, you describe what you want, collect the IDs, and stop them all in one shot.

### [Stop all instances in a VPC](#stop-all-instances-in-a-vpc)

```
1import boto32
3def stop_instances_in_vpc(vpc_id: str, region: str = 'us-east-1') -> list:4    """Stop all running instances in a given VPC."""5    ec2 = boto3.client('ec2', region_name=region)6
7    # Find every running instance in this VPC8    response = ec2.describe_instances(9        Filters=[10            {'Name': 'vpc-id', 'Values': [vpc_id]},11            {'Name': 'instance-state-name', 'Values': ['running']}12        ]13    )14
15    instance_ids = [16        inst['InstanceId']17        for r in response['Reservations']18        for inst in r['Instances']19    ]20
21    if not instance_ids:22        print(f'Nothing running in {vpc_id}.')23        return []24
25    print(f'Stopping {len(instance_ids)} instance(s) in {vpc_id}...')26    ec2.stop_instances(InstanceIds=instance_ids)27
28    return instance_ids29
30
31stopped = stop_instances_in_vpc('vpc-0abc12345def67890')32print(f'Stopped: {stopped}')
```

### [Stop all instances with a specific tag](#stop-all-instances-with-a-specific-tag)

```
1import boto32
3def stop_instances_by_tag(4    tag_key: str,5    tag_value: str,6    region: str = 'us-east-1',7    dry_run: bool = True8) -> list:9    """10    Stop all running instances that match a tag.11    Set dry_run=True to preview what would be stopped without actually doing it.12    """13    ec2 = boto3.client('ec2', region_name=region)14
15    response = ec2.describe_instances(16        Filters=[17            {'Name': f'tag:{tag_key}', 'Values': [tag_value]},18            {'Name': 'instance-state-name', 'Values': ['running']}19        ]20    )21
22    instance_ids = [23        inst['InstanceId']24        for r in response['Reservations']25        for inst in r['Instances']26    ]27
28    if not instance_ids:29        print(f'No running instances tagged {tag_key}={tag_value}.')30        return []31
32    if dry_run:33        print(f'[DRY RUN] Would stop {len(instance_ids)} instance(s):')34        for iid in instance_ids:35            print(f'  - {iid}')36        return instance_ids37
38    ec2.stop_instances(InstanceIds=instance_ids)39    print(f'Stopped {len(instance_ids)} instance(s) tagged {tag_key}={tag_value}.')40
41    return instance_ids42
43
44# Always preview before committing45stop_instances_by_tag('Environment', 'dev', dry_run=True)46
47# When you're confident, flip the flag48# stop_instances_by_tag('Environment', 'dev', dry_run=False)
```

> **Always build a `dry_run` mode into your bulk scripts.** It takes two minutes to add and can save you from a very bad day. Preview first, execute second.

* * *

## [Error handling: throttling, permissions, and invalid states](#error-handling-throttling-permissions-and-invalid-states)

_What happens when your Boto3 script hits an error, and how do you handle it cleanly?_

AWS APIs fail. Not often, but enough that your production scripts need to be ready for it. The three most common issues you’ll run into are rate limiting, missing permissions, and trying to do something that doesn’t make sense for the instance’s current state.

Here’s a function that handles all of them gracefully:

```
1import boto32import time3from botocore.exceptions import ClientError4
5def robust_stop_instance(6    instance_id: str,7    region: str = 'us-east-1',8    max_retries: int = 39) -> bool:10    """11    Stop an instance with sensible error handling and retry logic.12    Returns True on success, False if the operation can't be completed.13    """14    ec2 = boto3.client('ec2', region_name=region)15
16    for attempt in range(1, max_retries + 1):17        try:18            response = ec2.stop_instances(InstanceIds=[instance_id])19            state = response['StoppingInstances'][0]['CurrentState']['Name']20            print(f'Stopped {instance_id}. Current state: {state}')21            return True22
23        except ClientError as e:24            code = e.response['Error']['Code']25
26            if code in ('RequestLimitExceeded', 'Throttling'):27                # Back off exponentially and try again28                wait_time = 2 ** attempt29                print(f'Rate limited. Waiting {wait_time}s before retry {attempt}/{max_retries}...')30                time.sleep(wait_time)31
32            elif code == 'UnauthorizedOperation':33                # No point retrying this is a permissions issue34                print(f'Permission denied: {e.response["Error"]["Message"]}')35                print('Check the IAM policy on your role or profile.')36                return False37
38            elif code == 'IncorrectInstanceState':39                # Instance might already be stopped or terminated40                print(f'{instance_id} is in an unexpected state. Skipping.')41                return False42
43            elif code == 'InvalidInstanceID.NotFound':44                # Wrong region, or the instance no longer exists45                print(f'{instance_id} not found in {region}.')46                return False47
48            else:49                # Something unexpected surface it clearly50                print(f'Unexpected error [{code}]: {e}')51                raise52
53    print(f'Gave up after {max_retries} attempts.')54    return False
```

The key error codes to know:

-   **`RequestLimitExceeded` / `Throttling`:** You’re hitting the AWS API rate limit. Use exponential backoff and retry.
-   **`UnauthorizedOperation`:** The IAM role or user doesn’t have the right permission. No amount of retrying will fix this. You need to update the policy.
-   **`IncorrectInstanceState`:** You’re trying to do something the instance’s current state doesn’t allow, like stopping an instance that’s already stopped.
-   **`InvalidInstanceID.NotFound`:** The instance ID doesn’t exist in that region. Double-check both the ID and the region.

* * *

## [Frequently asked questions](#frequently-asked-questions)

Yes, and it’s pretty easy to do. Just create a separate client for each region you need. You can loop over a list of region names and run the same operations in each one. If you need it to go fast, `concurrent.futures` lets you run those calls in parallel.

```
1import boto32from concurrent.futures import ThreadPoolExecutor3
4regions = ['us-east-1', 'eu-west-1', 'ap-southeast-1']5
6def count_running(region):7    ec2 = boto3.client('ec2', region_name=region)8    resp = ec2.describe_instances(9        Filters=[{'Name': 'instance-state-name', 'Values': ['running']}]10    )11    count = sum(len(r['Instances']) for r in resp['Reservations'])12    print(f'{region}: {count} running instance(s)')13
14# Query all regions at the same time instead of one by one15with ThreadPoolExecutor() as pool:16    pool.map(count_running, regions)
```

At a minimum you’ll need `ec2:StartInstances`, `ec2:StopInstances`, `ec2:DescribeInstances`, and `ec2:DescribeInstanceStatus`. If you’re filtering by tags, add `ec2:DescribeTags` too. Scope permissions as tightly as you can using IAM condition keys, especially for production environments.

A fixed sleep is a guess. A waiter actually checks. Waiters poll the AWS API and return the moment the state changes, which means they’re faster when things go smoothly and more informative when they don’t. If the timeout is exceeded, you get a `WaiterError` you can handle, rather than a script that silently moves on assuming everything is fine.

Yes. `boto3.client('ec2')` is the low-level interface that maps directly to API calls and returns raw dictionaries. `boto3.resource('ec2')` gives you a higher-level, object-oriented interface with things like `ec2.Instance('i-0abc123')`. Both work, but the client is more flexible for filtering and bulk operations, which is why most automation scripts use it.

Mostly yes. `start_instances`, `stop_instances`, and `describe_instances` all work with spot instances. The main difference is that spot instances can be interrupted by AWS when capacity is reclaimed, so your automation should be ready for unexpected state changes. Use `describe_spot_instance_requests` to check spot-specific status and watch for interruption notices.

`describe_instances` only returns up to 1,000 results per call. For bigger environments, use a paginator instead of calling directly:

```
1import boto32
3ec2 = boto3.client('ec2', region_name='us-east-1')4paginator = ec2.get_paginator('describe_instances')5
6instances = []7# paginate() handles NextToken automatically no manual looping needed8for page in paginator.paginate(Filters=[{'Name': 'instance-state-name', 'Values': ['running']}]):9    for reservation in page['Reservations']:10        instances.extend(reservation['Instances'])11
12print(f'Total running instances: {len(instances)}')
```

The paginator handles `NextToken` automatically, so you’ll always get everything without extra logic.

Use the `dry_run` pattern shown in the bulk operations section. Run with `dry_run=True` first to see exactly which instances would be affected before you commit. Beyond that, test in a staging account or a non-production VPC. Some Boto3 calls also support a `DryRun=True` parameter at the API level, which validates your permissions without making any changes.

* * *

## [References](#references)

-   [Boto3 Documentation EC2 Client](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html)
-   [Boto3 Documentation Waiters](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/clients.html#waiters)
-   [Boto3 Documentation Paginators](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/paginators.html)
-   [Boto3 Documentation Session and Credential Configuration](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html)
-   [AWS EC2 API Reference DescribeInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstances.html)
-   [AWS EC2 API Reference StartInstances & StopInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_StartInstances.html)
-   [AWS IAM Best Practices](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html)
-   [AWS IAM Roles for EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html)
-   [AWS EC2 Instance Lifecycle](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-lifecycle.html)
-   [AWS EC2 Tagging Your Resources](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Tags.html)
-   [Botocore Exceptions Reference](https://botocore.amazonaws.com/v1/documentation/api/latest/reference/exceptions.html)
-   [AWS EC2 Spot Instance Interruptions](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-interruptions.html)
-   [Python `concurrent.futures` ThreadPoolExecutor](https://docs.python.org/3/library/concurrent.futures.html#threadpoolexecutor)
-   [AWS CLI Configuration and Credential Files](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html)
-   [AWS Well-Architected Framework Operational Excellence Pillar](https://docs.aws.amazon.com/wellarchitected/latest/operational-excellence-pillar/welcome.html)

Was this useful?

## Tags

[#AWS](/codesnippets/tags/aws)[#EC2](/codesnippets/tags/ec2)[#Boto3](/codesnippets/tags/boto3)[#Python](/codesnippets/tags/python)[#DevOps](/codesnippets/tags/devops)[#Automation](/codesnippets/tags/automation)[#IAM](/codesnippets/tags/iam)[#Cloud](/codesnippets/tags/cloud)[#Infrastructure](/codesnippets/tags/infrastructure)

## Share

[Facebook](https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fmkabumattar.com%2Fcodesnippets%2Fpost%2Faws-ec2-instance-management-boto3-python "Share on Facebook")[Twitter](https://twitter.com/intent/tweet/?text=AWS%20EC2%20Instance%20Management%20with%20Boto3%3A%20Start%2C%20Stop%2C%20and%20Query%20Instances&url=https%3A%2F%2Fmkabumattar.com%2Fcodesnippets%2Fpost%2Faws-ec2-instance-management-boto3-python "Share on Twitter")[LinkedIn](https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fmkabumattar.com%2Fcodesnippets%2Fpost%2Faws-ec2-instance-management-boto3-python&title=AWS%20EC2%20Instance%20Management%20with%20Boto3%3A%20Start%2C%20Stop%2C%20and%20Query%20Instances&summary=Learn%20how%20to%20automate%20AWS%20EC2%20instance%20management%20using%20Python%20and%20Boto3.%20This%20guide%20covers%20authentication%20with%20IAM%20roles%2C%20starting%20and%20stopping%20instances%2C%20using%20waiters%2C%20filtering%20by%20tags%2C%20running%20bulk%20operations%2C%20and%20handling%20API%20errors.%20Practical%20code%20examples%20included%20for%20DevOps%20engineers%20and%20cloud%20developers&source=https://mkabumattar.com "Share on LinkedIn")[WhatsApp](https://wa.me/?text=AWS%20EC2%20Instance%20Management%20with%20Boto3%3A%20Start%2C%20Stop%2C%20and%20Query%20Instances%20https%3A%2F%2Fmkabumattar.com%2Fcodesnippets%2Fpost%2Faws-ec2-instance-management-boto3-python "Share on WhatsApp")[Telegram](https://t.me/share/url?url=https%3A%2F%2Fmkabumattar.com%2Fcodesnippets%2Fpost%2Faws-ec2-instance-management-boto3-python&text=AWS%20EC2%20Instance%20Management%20with%20Boto3%3A%20Start%2C%20Stop%2C%20and%20Query%20Instances "Share on Telegram")[Reddit](https://www.reddit.com/submit?url=https%3A%2F%2Fmkabumattar.com%2Fcodesnippets%2Fpost%2Faws-ec2-instance-management-boto3-python&title=AWS%20EC2%20Instance%20Management%20with%20Boto3%3A%20Start%2C%20Stop%2C%20and%20Query%20Instances "Share on Reddit")[Hacker News](http://news.ycombinator.com/submitlink?u=https%3A%2F%2Fmkabumattar.com%2Fcodesnippets%2Fpost%2Faws-ec2-instance-management-boto3-python&t=AWS%20EC2%20Instance%20Management%20with%20Boto3%3A%20Start%2C%20Stop%2C%20and%20Query%20Instances "Share on Hacker News")[Pinterest](https://pinterest.com/pin/create/button/?url=https%3A%2F%2Fmkabumattar.com%2Fcodesnippets%2Fpost%2Faws-ec2-instance-management-boto3-python&media=&description=Learn%20how%20to%20automate%20AWS%20EC2%20instance%20management%20using%20Python%20and%20Boto3.%20This%20guide%20covers%20authentication%20with%20IAM%20roles%2C%20starting%20and%20stopping%20instances%2C%20using%20waiters%2C%20filtering%20by%20tags%2C%20running%20bulk%20operations%2C%20and%20handling%20API%20errors.%20Practical%20code%20examples%20included%20for%20DevOps%20engineers%20and%20cloud%20developers "Share on Pinterest")[Email](<mailto:?subject=AWS%20EC2%20Instance%20Management%20with%20Boto3%3A%20Start%2C%20Stop%2C%20and%20Query%20Instances&body=Check out this article: https%3A%2F%2Fmkabumattar.com%2Fcodesnippets%2Fpost%2Faws-ec2-instance-management-boto3-python>)

## Comments

## You might also enjoy

More posts on similar topics

[![List S3 Buckets](/_astro/hero.BsiJ6hry_1X9XLn.webp)](/codesnippets/post/python-list-s3-buckets)

## [List S3 Buckets](/codesnippets/post/python-list-s3-buckets)

-   [Mohammad Abu Mattar](/authors/mohammad-abu-mattar)
-   [Aws](/codesnippets/categories/aws)
-   [Python](/codesnippets/categories/python)
-   [Devops](/codesnippets/categories/devops)

Overview Multi-profile S3 management Ever juggled multiple AWS accounts and needed a quick S3 bucket inventory across all of them? This Python script handles it. Use case Perfect for or

[#Python](/codesnippets/tags/python)[#Boto3](/codesnippets/tags/boto3)[#AWS](/codesnippets/tags/aws)+5 tags

[read more](/codesnippets/post/python-list-s3-buckets)

[![AWS Secrets Manager](/_astro/hero.BIDl4oI2_Z1yJEXf.webp)](/codesnippets/post/nodejs-aws-secrets-manager)

## [AWS Secrets Manager](/codesnippets/post/nodejs-aws-secrets-manager)

-   [Mohammad Abu Mattar](/authors/mohammad-abu-mattar)
-   [Aws](/codesnippets/categories/aws)
-   [Devops](/codesnippets/categories/devops)

Loading secrets in a Node.js app without exposing them If you're still storing API keys or database credentials in .env files or hardcoding them into your codebase, it's time for a better appro

[#NodeJS](/codesnippets/tags/nodejs)[#TypeScript](/codesnippets/tags/typescript)[#AWS](/codesnippets/tags/aws)+3 tags

[read more](/codesnippets/post/nodejs-aws-secrets-manager)

[![Check S3 Bucket Existence](/_astro/hero.CWiO4GWV_1YUYTb.webp)](/codesnippets/post/bash-s3-bucket-exists)

## [Check S3 Bucket Existence](/codesnippets/post/bash-s3-bucket-exists)

-   [Mohammad Abu Mattar](/authors/mohammad-abu-mattar)
-   [Aws](/codesnippets/categories/aws)
-   [Shell scripting](/codesnippets/categories/shell-scripting)
-   [Devops](/codesnippets/categories/devops)

Quick Tip Don't let your deployment blow up because of a missing S3 bucket. This Bash script lets you check if a bucket exists before anything fails. The Problem Missing bucket failure

[#Bash](/codesnippets/tags/bash)[#AWS](/codesnippets/tags/aws)[#DevOps](/codesnippets/tags/devops)+3 tags

[read more](/codesnippets/post/bash-s3-bucket-exists)

[![Multi-Environment Secret Management with HashiCorp Vault](/_astro/hero.B4H3tk7I_1BuPOM.webp)](/codesnippets/post/hashicorp-vault-multi-environment-secrets)

## [Multi-Environment Secret Management with HashiCorp Vault](/codesnippets/post/hashicorp-vault-multi-environment-secrets)

-   [Mohammad Abu Mattar](/authors/mohammad-abu-mattar)
-   [Security](/codesnippets/categories/security)
-   [Devops](/codesnippets/categories/devops)

Managing secrets safely across multiple environments with HashiCorp Vault Storing secrets in .env files, hardcoding them, or even using separate secret managers per environment creates security

[#Vault](/codesnippets/tags/vault)[#SecretsManagement](/codesnippets/tags/secretsmanagement)[#MultiEnvironment](/codesnippets/tags/multienvironment)+3 tags

[read more](/codesnippets/post/hashicorp-vault-multi-environment-secrets)

[![Bash Retry Function: Automatically Retry Failing Commands with Exponential Backoff](/_astro/hero.Dap62rVN_Z1q0nar.webp)](/codesnippets/post/bash-retry-function-exponential-backoff)

## [Bash Retry Function: Automatically Retry Failing Commands with Exponential Backoff](/codesnippets/post/bash-retry-function-exponential-backoff)

-   [Mohammad Abu Mattar](/authors/mohammad-abu-mattar)
-   [Devops](/codesnippets/categories/devops)
-   [Shell scripting](/codesnippets/categories/shell-scripting)
-   [Automation](/codesnippets/categories/automation)

Quick Tip Wrap any flaky command in one reusable retry function and stop re-running red pipelines by hand. The Problem The Problem Some commands fail for reasons that have nothing to

[#Bash](/codesnippets/tags/bash)[#Retry](/codesnippets/tags/retry)[#Exponential Backoff](/codesnippets/tags/exponential-backoff)+3 tags

[read more](/codesnippets/post/bash-retry-function-exponential-backoff)

[![Essential Bash Variables for Every Script](/_astro/hero.B4bDowyY_YQpD7.webp)](/codesnippets/post/essential-bash-variables)

## [Essential Bash Variables for Every Script](/codesnippets/post/essential-bash-variables)

-   [Mohammad Abu Mattar](/authors/mohammad-abu-mattar)
-   [Shell scripting](/codesnippets/categories/shell-scripting)
-   [Devops](/codesnippets/categories/devops)

Overview Quick Tip You know what's worse than writing scripts? Writing scripts that break every time you move them to a different machine. Built-in Bash variables fix that. The problem wi

[#Bash](/codesnippets/tags/bash)[#Shell Scripting](/codesnippets/tags/shell-scripting)[#Linux](/codesnippets/tags/linux)+4 tags

[read more](/codesnippets/post/essential-bash-variables)

6 related posts
