AT commands (or Hayes commands) form the language used to communicate with cellular modems. Whether you’re developing an IoT device, working with M2M applications, or trying to understand how your device talks to cellular networks, understanding “ATtention” or AT commands is essential.
In this comprehensive guide, I’ll walk you through what AT commands are, how they work, and provide practical examples to get you started.
Table of Contents
What are AT commands?
AT commands are a specific command language originally developed for the Hayes Smartmodem in the 1980s. The name “AT” comes from the fact that each command line starts with “AT,” which stands for “Attention.”
AT commands became the standard, text-based way to communicate with modems through the computer via a serial terminal and have evolved to control modern cellular modems in phones, IoT devices, and other connected products.
A typical AT command might look like: AT+CREG?
(which checks the network registration status).
Do different manufacturers have different AT commands?
You’re probably looking to execute commands to your manufactured device by SIMCom, Quectel, Gemalto, U-Blox, and Telit, just to name a few.
Good news: there’s a shared standard across the industry. However, the specific command set can vary between manufacturers and models. Examples include AT+QIOPEN
for Quectel modules and AT+CIPPING
for SIMCom modules.
Additionally, some commands in the standard are optional and may not be present on all modems.
💡AT commands standard: Most cellular modules implement a core set of standardized AT commands. These standards are defined by ITU-T V.250 and 3GPP TS 27.007 / 27.005. ITU (International Telecommunication Union) is the primary standards body for telecom, while 3GPP (3rd Generation Partnership Project) is also crucial. The ITU V.250 standard hasn’t been updated since 2003 and is quite stable. The 3GPP standard, however, has different versions (releases), and commands specified in the newest release might not be available on older modems.
To read more about telecommunication standardizations, this article paints the full picture.
The role of AT Commands in IoT connectivity
If you’re developing any device that needs cellular connectivity (2G, 3G, 4G, LTE, LTE-M, NB-IoT, and even for 5G modems, to name some), AT commands are your primary interface to the modem. They allow you to:
- Configure the modem
- Establish network connections
- Send/receive SMS messages
- Make voice calls
- Transfer data
- Query signal strength and network status
- Perform diagnostics
From setting the Access Point Name (APN), which is a logical name used to select the gateway to the external packet data network, to dialing a data connection, AT commands are the mechanism used to configure and control the modem to get online.
How do AT commands work?
Understanding how AT commands work requires looking at their syntax and interaction flow. Let’s go through them below.
AT commands syntax basics
AT commands have a specific syntax to function correctly, which is typically as seen below:
AT<COMMAND><SUFFIX><DATA>
The basic format is AT followed by the command, a suffix indicating the command type (e.g., setting a value, querying information), and sometimes additional data. Each command line ends with a carriage return, but multiple commands can be strung together on a single line using semicolons.
Core format and structure
- All commands start with
"AT"
(not case-sensitive) followed by an optional+
and then the command:
E.g. AT+CREG
(or at+creg?
or At+CrEg?
) and ATZ
- Arguments for an AT command are comma-separated
E.g. AT+CGDCONT=1,"IP","onomondo"
Setters, getters, and testers
Character/s | What it does | Example |
---|---|---|
= | Sets a value | AT+CGATT=1 |
? | Gets the current status | AT+CREG? |
=? | Queries supported values/ranges for possible arguments | AT+CREG=? |
Chaining Commands
Use of ;
: AT commands which are to be executed sequentially right after each other can be delimited with a ;
and only the first command should include AT
E.g. AT+CREG?;+GGREG?
AT Command responses
Response | What it means | Example |
---|---|---|
OK | Successful command execution | AT+CGATT=1 |
ERROR | Failed command | AT+CREG? |
+CME ERROR: <code> | Extended error for mobile equipment | |
+CMS ERROR: <code> | Error related to SMS functionality | |
ABORTED | The command has been aborted (applies only to some modems) | AT+CREG=? |
Other responses | When the responses above don’t apply, it could prompt for more data |
According to U-Blox, before each transmitted AT command the device communicating with the modem should:
- Wait 20 ms
- Flush the buffer
This helps the device handle unsolicited result codes (URCs), which the modem sends for various events if enabled. A typical URC would be the one coming from network registrations both data- and phone/SMS wise.
Here’s what it looks like when you issue a command to register on the network — with URC and without URC:
Example: with URC after having issued a command to register on the network | at+creg=1 // enable URC for circuit-switched network registrations |
Example: without URC after having issued a command to register on the network | at+cops=0 // register to GSM/UMTS/EPS network with automatic network selection |
2 types of AT commands
All AT commands generally fall into 2 categories: basic and extended.
- Basic AT commands: broadly speaking, if a command does not start with
+
, this is a basic command.
- Extended AT commands: Conversely, those starting with
+
are considered extended commands (and generally, all GSM AT commands are considered extended commands).
Different categories of AT commands
The command types above generally classify them based on how you form the command (with or without +
at the beginning), AT command categories classify them further based on what you want to execute on, which are:
- Test commands
- Read commands
- Set commands
- Execution commands
Category | What is it for | Suffix | Syntax | Example |
---|---|---|---|---|
Test | To query the modem about its capabilities or supported parameter ranges | =? | AT<COMMAND NAME>=? | ATD=? |
Read | To read the current status or configuration of a setting | ? | AT<COMMAND NAME>? | AT+CBC? |
Set | To configure parameters or settings on the modem | = | AT<COMMAND NAME>=value1, value2, …, valueN | AT+CSCA=”+123456789”, 120 |
Execution | To trigger a specific action on the modem, such as dialing a number | none | AT<COMMAND NAME>=parameter1,…, parameterN | AT+CMSS=1,”+123456789”, 120 |
Practical AT commands examples
If you have a 3GPP/ITU-compatible cellular modem, chances are, these common AT commands are applicable. We will also cover some basic commands that are manufacturer-specific.
1. Standardized list of AT Commands: your cross-modem toolkit
First let’s familiarize ourselves with the AT commands involved in this process, their syntax, their values, and then we’ll see them in action later on in this guide.
A. Establishing a data connection
Let’s break this step down further into choosing, registering, defining PDP, activating/deactivating PDP context, and checking status.
AT+COPS
What is it for: Choose the network operator to use and register on the circuit-switched network.
Setting syntax | AT+COPS=[<mode>[,<format>[,<oper>[,<AcT>]]] |
Example response | AT+COPS=? ‘s response will be a list (denoted with [element_1, element_2, ..., element_n]) of element values. |
Note: Even though it is not documented in the standards, this command also goes ahead and connects to the circuits-switched network of the chosen provider (phone/SMS connection, also called GSM connection in our network logs). As an additional warning from our engineers, telling your modems to attach/detach is not always a good practice.
For a closer look, we covered the modes, parameters, and some examples in this dedicated blog for AT+COPS.
AT+CREG
What is it for: Circuit-switched network registration status, which is the connection that provides the phone/SMS service.
Testing syntax | AT+CREG=<n> |
Example response | +CREG: <n>,<stat>[,[<lac>],[<ci>],[<AcT>][,<cause_type>,<reject_cause>]] |
To get a practical overview on how to use this command including the variables, check out this AT+CREG blog.
AT+CEREG
What is it for: Registration status of the device for LTE or newer cellular network technologies.
Testing syntax | AT+CEREG=? |
Example response |
|
Full command details (variables) are here on this dedicated AT+CEREG blog.
AT+CGREG
What is it for: Packet-switched network registration status.
Testing syntax | AT+CGREG=? |
Example response |
|
Note: Identical to AT+CREG but for the packet-switched network instead, i.e. data connection
CREG vs CGREG vs CEREG, what are the difference between these AT commands? Find the answer and variables in this in-depth AT+CGREG blog.
AT+CGDCONT
What is it for: Define packet data protocol (*PDP) context
Setting syntax | AT+CGDCONT=<cid>,<PDP_TYPE>,<APN> |
Read syntax | AT+CGDCONT=<cid>,<PDP_TYPE>,<APN>,<PDP_addr> |
For both syntaxes the values are:
<cid>: integer type; specifies a particular PDP context definition (you can multiple PDP context)
<PDP_type>: string type; specifies the type of packet data protocol. The default value is manufacturer-specific.
X.25 ITU-T/CCITT X.25 layer 3 (Obsolete)
IP Internet Protocol (IETF STD 5 [103])
IPV6 Internet Protocol, version 6 (see RFC 2460 [106])
IPV4V6 Virtual <PDP_type> introduced to handle dual IP stack UE capability. (See 3GPP TS 24.301 [83])
OSPIH Internet Hosted Octect Stream Protocol (Obsolete)
PPP Point to Point Protocol (IETF STD 51 [104])
Non-IP Transfer of Non-IP data to external packet data network (see 3GPP TS 23.401 [82]) Ethernet
Ethernet protocol (IEEE 802.3)
Unstructured Transfer of Unstructured data to the Data Network via N6 (see 3GPP TS 23.501 [165])
<APN>: string type; a logical name that is used to select the GGSN or the external packet data network.
<PDP_addr>: string type; identifies the MT in the address space applicable to the PDP.
*A PDP context is a piece of information that is needed inside the mobile core in order for it to set up a data session. From the device point of view, this is where the access point name (APN) is set. The command in itself does not activate any signalling.
For EPS and 5G, this command instead sets the PDN connection and PDU session respectively.
AT+CGACT
What is it for: Activate/deactivate PDP context
Setting syntax | AT+CGACT=<state>,<cid> |
Example response | (list of) <state>,<cid> |
For both syntaxes the values are:
<state>: integer type; indicates the state of PDP context activation.
0 deactivated
1 activated
<cid>: integer type; specifies a particular PDP context definition (see the +CGDCONT and +CGDSCONT commands).
If an activation of a PDP context is issued and the modem is not connected to the packet-switched (PS) network then it will first attach to the PS network, this is equivalent to running AT+CGATT=1
AT+CGATT=<state>
attaches or detaches to the PS network depending on the <state>
Using the AT command sequence in this blog, you can establish a data connection to your cellular IoT connectivity provider to test modem connectivity.
Seeing it in action
In order to get a data connection we have to do the following:
AT
– check the connection to the modem, should respond OK (this step is not strictly needed)AT+COPS=0
– choose network operator and register on the circuit-switched network- Wait for
AT+CREG
to respond x,5 AT+CGDCONT=1,"IP","onomondo"
– define PDP context (this step could come prior to AT+COPS=0)AT+CGACT=1,1
– activate PDP context (will also call AT+CGATT=1, which is a network attach command if not already attached)- Wait for
AT+CGREG
to respondx,5
This procedure could be used to test whether or not there are any problems in terms of just getting a connection.
This is the result using the SIM808 modem:
Since the SIM has already been attached at some point to the network operator a new authentication is not needed. We first see new signalling when the modem actually attaches to the packet-switched network, i.e. when AT+CGACT=1,1
is issued.
Why a new GSM/circuit-switched connection, which provides phone/SMS services, is not established is a bit of a mystery. In theory, we should see a new GSM connection once the AT+CREG?
command responds with x,5
.
B. Establishing a PPP Connection
For this step, most of the AT commands used are similar to what was used for the previous step (establishing a data connection), with the addition of this:
ATD<number> # Dials the given number
In order to get a PPP connection we have to do the following:
AT+COPS=0
– choose network operator and register on network- Wait for
AT+CREG
andAT+CEREG
to respondx,5
AT+CGDCONT=1,"IP","onomondo"
– define PDP context (as an example)AT+CGACT=1,1
– activate PDP context (will also callAT+CGATT=1
, which is a network attach command if not already attached)ATD*99#
– dial up provider (*99#
is the standard number to dial up the operator)- Start PPP protocol
This procedure is the only generic way of getting a usable connection from a device. The only issue with this approach is that the device has to support the PPP-, TCP- and UDP protocols – this is not viable for teeny tiny devices, but most microcontrollers which can run Mongoose OS, FreeRTOS, or the likes will be able to use it.
This procedure is actually what is being carried out by Linux’s PPP daemon, pppd, on the deveyes and watchdogs.
Also as a side note then some modems might require that the baud rate used with the serial connection be fixed to a specific value.
C. Getting the modem and SIM information
To get the information about the state of your modem and SIM, these AT commands are nice to know.
Let’s divide them into three:
- Reset commands
- Modem meta-data
- SIM and device identifiers
Resetting the modem profile
There are two ways of getting the modem into a factory setting:
ATZ[value] # Resetting the modem into a user-specified profile
AT&F[value] # Factory resetting the modem
The settings that will change are not clearly stated in the standard but check with the settings with your modem. Additionally, the reset will never trigger a change in the baud rate.
Get the modem meta-data
For more information about your hardware, here are some helpful AT commands:
ATI[value] # Get the modem information (e.g. SIM808 R14.18)
AT+GMI # Determine the identity of the modem manufacturer (e.g. SIMCOM_Ltd)
AT+GMM # Get the modem model (e.g. SIMCOM_SIM808)
AT+GMR # Get the modem version (e.g. Revision:1418B03SIM808M32)
AT+CGMR # Get firmware version
SIM and device identifiers
Use these commands to help you identify some basic SIM information:
AT+CIMI # Get the International Mobile Subscriber Identity (IMSI)
AT+CGSN # Get the International Mobile station Equipment Identity (IMEI)
AT+CCID # Get the Integrated Circuit Card Identifier (ICCID) (Not standardized, check manufacturer)
D. Sending an SMS
To send a text message:
AT+CMGF=1 # Set SMS to text mode (vs. PDU mode)
AT+CSCA="+1234567890" # Set SMS center number if needed
AT+CSAS # Saves SMS settings, SMSC number to the SIM
AT+CMGS="recipient_number" # Start SMS to recipient
> Your message text here # Type message after '>' prompt
# Press Ctrl+Z to send
Now, you can try it out using the AT+CMGS=<number>
command, e.g.:
AT+CMGS="1234"
> saying hello from modem!
+CMGS: 11
OK
In Onomondo, the SMS will then appear in your webhook.
Start testing Onomondo for free
Ready to experience next-generation IoT connectivity? Create an account, explore the platform, and start testing Onomondo’s IoT SIM cards for free.
2. Manufacturer-Specific AT Commands (SIMCom and Quectel)
Other common commands, such as pinging a server and looking into TCP/UDP communication varies depending on the modem manufacturer. Our examples below are for SIMCom SIM808 and Quectel EC25-E and might not work for all of their modems but should at least work for modems on the same series.
A. Pinging a server
- For SIMCom modems:
In order to use any of the subsequent SIMCom’s AT commands an active PDP context is needed, but it has to be established using SIMCom’s own special AT commands12. Here’s the procedure:
AT+CSTT="your_apn" # Start task with APN
AT+CIICR # Bring up wireless connection
AT+CIFSR # Get local IP address (mandatory)
AT+CIPPING=<host>[,<retryNum>[,<dataLen>[,<timeout>[,<ttl>]]]]
# Ping Google's DNS server
The values for the AT+CIPPING syntax are:
<host> Address of the remote host, string type. This parameter can be either:
- IP address in the format:”xxx.xxx.xxx.xxx”
- Host name solved by a DNS query
<retryNum> The number of Ping Echo Requset to send
1-100 Default: 4
<dataLen> The length of Ping Echo Request data
0-1024 Default: 32
<timeout> The timeout, in units of 100 ms, waiting for a single Echo Reply
1-600 Default: 100(10 seconds)
<ttl> Time to live
1-255 Default: 64
- For Quectel modems:
For these Quectel specific AT commands to work, an activated PDP context is needed, i.e. an active data session, which was discussed in the “establishing a data connection” part. Then you can run the commands accordingly.
AT+QPING=<contextID>,<host>[,<timeout>[,<pingnum>]]
# Pings a remote server
The values for the AT+QPING syntax are:
<contextID> Integer type. The context ID. The range is 1-16.
<host> The host address in string type. The format is a domain name or a dotted decimal IP address.
<timeout> Integer type. Set the maximum time to wait for the response of each ping request. The range is 1-255, and the default value is 4. Unit:second.
<pingnum>Integer type. Set the maximum number of time for sending ping request. The range is 1-10, and the default value is 4.
B. TCP/UDP communication
To send data over TCP (again, varies by manufacturer):
- SIMCom example:
AT+CIPMODE=<mode>
# Set transparent (1) or non-transparent mode (0)
AT+CIPSTART=[n,]<mode>,<host>,<port>
# The setting syntax. Connect to server on port 80 ([0…5]<”TCP” or “UDP”>,<remote server IP address>,<Remote server port>
AT+CIPSEND
# Send data through TCP or UDP. AT+CIPSEND[=<length>|] (in case of multiple connections a <n> variable also need to be set.
> GET / HTTP/1.1
# Your data (followed by Ctrl+Z)
Host: server.example.com
AT+CIPSERVER=<mode>[,<port>]
# Set up a TCP server. `port` is not needed when closing it =<mode> 0 Close server, 1 Open server, <port> 1..65535 Listening port
- Quectel example:
To open a socket service:
AT+QIOPEN=<contextID>,<connectID>,<service_type>,<host>,<remote_port>[,<local_port>][,<access_mode>]
Here are its variables:
<contextID> Integer type. The context ID. The range is 1-16. (the PDP context ID)
<connectID> Integer type. The socket service index. The range is 0-11.
<service_type> String type. The socket servicetype.
“TCP” Start a TCP connection as a client
“UDP” Start a UDP connection as a client
“TCP LISTENER” Start a TCP server to listen to TCP connection
“UDP SERVICE” Start a UDP service
<host> String type. If <service_type> is TCP or UDP, it indicates the IP address (could also be a domain name) of remote server, such as “220.180.239.212”. If <service_type> is TCP LISTENER or UDP SERVICE, please enter “127.0.0.1”..
<remote_port> The port of the remote server, only valid when <service_type> is “TCP” or “UDP”. The range is 0-65535.
<local_port> The local port. The range is 0-65535. If <service_type> is “TCP LISTENER” or “UDP SERVICE”, this parameter must be specified. If <service_type> is “TCP” or “UDP”, if <local_port> is 0, then the local port will be assigned automatically. Otherwise the local port is assigned as specified.
<access_mode> Integer type. The data access mode of the socket service.
0 Buffer access mode
1 Direct push mode
2 Transparent access mode
AT+QIRD
– to retrieve the received data from a socket
AT+QIRD=<connectID>[,<read_length>]
# Retrieve the received data from a socket =<socket service index from 0-11>[,<0-1500 byte range>]
Advanced features and debugging tips
Establish a connection to the network: Signalling investigation
In order to understand what is going on with each AT commands the generic procedure for establishing a data connection, as discussed earlier, was carried out on Quectel’s EC25-E modem. The test was done with a new network operator so that the authorization signalling and so on would show:
AT+COPS=? // check for available network operators
+COPS: (2,"TDC","TDC","23801",2),(1,"TDC","TDC","23801",0),(1,"3 DK","3 DK","23806",2),(1,"Telenor DK","TelenoDK","23802",2),(1,"Telia DK","Telia","23820",2),()
OK
AT+COPS=1,0,"3 DK" // manually select 3 DK network
OK
AT+CGDCONT? // check PDP contexts
+CGDCONT: 1,"IP","","0.0.0.0",0,0,0,0 // nothing, this means the device does not have a data connection
OK
AT+CGACT? // check defined PDP contexts' status
+CGACT: 1,0 // PDP context 1 is not activated
OK
AT+CGATT? // check packet-switched (PS) network status
+CGATT: 0 // the modem is not connected to the PS network
OK
AT+CREG? // check circuit-switched (CS) network status
+CREG: 0,5 // URC disabled, roaming on CS network
OK
AT+CGREG? // check packet-switched (PS) network status
+CGREG: 0,2 // URC disabled, searching
OK
In Onomondo, we have a feature that allows you to see the network logs. When the commands above were executed, here’s what the logs show:

Then the following was executed:
AT+CGDCONT=1,"IP","onomondo" // define PDP context
OK
AT+CGACT=1,1 // activate PDP context (will also do a AT+CGATT=1)
OK
AT+CGREG? // check packet-switched network status
+CGREG: 0,5 // URC disabled, roaming (this is good we are connected)
OK
Which resulted in the following new network logs:


Here’s a recap of what happened during this procedure:

Adding a network preference list
Most networks have a list of preferred networks their SIMs can attach to, this is called the PLMN list.
Using AT commands allow you to change your prefered networks with these 2 commands:
AT+CPOL
(the simple way)AT+CSIM
(the complex way)
We created a full tutorial to use these AT commands in this PLMN list blog, that also includes a template you can use to help you manage your list.
Debugging tips
- Enable verbose error reporting with
AT+CMEE=2
to get detailed error messages - Check signal quality with
AT+CSQ
before attempting connections - Enable network registration notifications with
AT+CREG=1
to receive real-time updates - Verify APN settings with
AT+CGDCONT?
- Check if the modem is attached to the packet network with
AT+CGATT?
References
- This guide originally appeared on the author’s GitHub.
- https://www.itu.int/rec/T-REC-V.250/en
- https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=1515
- https://www.u-blox.com/sites/default/files/AT-CommandsExamples_AppNote_(UBX-13001820).pdf
- Exploratory Analysis of a GGSN’s PDP Context Signaling Load, http://downloads.hindawi.com/journals/jcnc/2014/526231.pdf
- https://www.cika.com/soporte/Information/GSMmodules/Quectel/AppNotes/Quectel_GSM_PPP_Application_Note.pdf
- https://zoomtel.zendesk.com/hc/en-us/articles/212403243-Mobile-broadband-service-provider-settings
- https://simcom.ee/documents/SIM7100E/SIM7100_AT%20Command%20Manual_V1.01.pdf
- https://www.telit.com/wp-content/uploads/2018/03/Telit-LN940-SERIES-AT-Command-User-Guide-REV1.4.pdf
- http://www.python-exemplary.com/download/sim800_series_tcpip_application_note_v1.00.pdf
- https://simcom.ee/documents/SIM900/SIM900_PING_AT%20Command%20Manual_V1.00.pdf (even though it is for the SIM900’s series it still works for the SIM800 series)
- https://www.elecrow.com/wiki/images/2/20/SIM800_Series_AT_Command_Manual_V1.09.pdf
- https://sixfab.com/wp-content/uploads/2018/09/Quectel_EC2xEG9xEM05_TCPIP_AT_Commands_Manual_V1.0.pdf