M-codes are machine functions that do not command axis motion. The core set is the same on most CNC controls: M00 program stop, M01 optional stop, M03 / M04 / M05 spindle clockwise / counter-clockwise / stop (speed in rpm from the S word), M06 tool change, M08 coolant on, M09 coolant off and M30 program end and reset. Beyond that the controls differ: Grbl has no M6 tool change and ignores M1; Haas uses M07 for shower coolant; and on Marlin 3D printers M30 deletes a file from the SD card while M104/M109 set the hotend temperature instead of working a probe arm, as they do on a Haas mill. Below: the four controls side by side, then the full Haas mill and lathe, LinuxCNC and Grbl lists from each maker's documentation. To see what a program's M-codes do line by line, paste it into the G-code Explainer & Simulator.
Core M-codes (Haas and LinuxCNC agree)
| Code | Name | What it does |
|---|---|---|
| M00 | Program stop | Stops the program; Cycle Start continues from the next block. Haas M00 also stops the axes, spindle and coolant. |
| M01 | Optional stop | Same as M00, but only when the Optional Stop switch is on. |
| M02 | Program end | Ends the program. |
| M03 | Spindle clockwise | Starts the spindle forward at the S speed (S5000 = 5,000 rpm). |
| M04 | Spindle counter-clockwise | Starts the spindle in reverse at the S speed. |
| M05 | Spindle stop | Stops the spindle (Haas waits for it to stop). |
| M06 | Tool change | Puts the tool selected by the T word in the spindle, e.g. M06 T12 (Haas), or T12 M6 (LinuxCNC). |
| M08 | Coolant on | Flood coolant on. |
| M09 | Coolant off | Turns coolant off. |
| M19 | Orient spindle | Turns the spindle to a fixed angle between 0 and 360°. |
| M30 | Program end and reset | Ends the program and makes it ready to run again from the top. |
| M98 | Subprogram call | Calls another program (Haas: P = program number, L = 1–99 repeats). |
| M99 | Subprogram return | Returns to the calling program (Haas: in a main program it loops back to the start). |
Numbers that go with M-codes
| Word | Used with | Meaning | Unit |
|---|---|---|---|
| S | M03 / M04 | Spindle speed (Haas: S5000 = 5,000 rpm) | rpm |
| T | M06 | Tool number (LinuxCNC: the pocket number in the carousel) | number |
| P | M19 (Haas) | Orient angle, whole degrees 0–360 | degrees (°) |
| R | M19 (Haas, LinuxCNC) | Orient angle; Haas allows two decimals (0.00–360.00) | degrees (°) |
| Q | M19 (LinuxCNC) | Time to wait for the spindle to orient before an error | seconds (s) |
| P | M08 (Haas variable flow) | P0 / P1 / P2 = low / normal / high pressure, pump at 50 / 60 / 80 | Hz |
| P | M97 / M98 (Haas) | N line number (M97) or program number (M98) to call | number |
| L | M97 / M98 (Haas) | Number of times to repeat the call, 1–99 | count |
Same code, four controllers
| Code | Haas mill | LinuxCNC | Grbl 1.1 | Marlin 2.x |
|---|---|---|---|---|
| M0 | Stop program | Pause | Pause (feed hold) | Stop, wait for user |
| M1 | Optional stop | Optional pause | Ignored | Same as M0 (deprecated) |
| M2 | Program end | End, reset modes | End, reset modes | Not listed |
| M3 / M4 / M5 | Spindle fwd / rev / stop | Spindle CW / CCW / stop | Spindle CW / CCW / stop | Spindle or laser (build option) |
| M6 | Tool change | Tool change | Not supported (error:20) | Not listed; T0–T7 select a tool |
| M7 | Shower coolant | Mist coolant | Mist (compile option) | Mist (build option) |
| M8 | Coolant on | Flood on | Flood on | Flood (build option) |
| M9 | Coolant off | Mist and flood off | Mist and flood off | Coolant off (build option) |
| M19 | Orient spindle | Orient spindle | Not supported | Not listed |
| M30 | End and reset | End, pallet change, reset | Same as M2 | Delete SD file |
| M48 | Check pallet program | Overrides on | Not supported | Probe repeatability test |
| M97 | Local subprogram | Not listed | Not supported | Not listed |
| M98 / M99 | Sub call / return | Sub call / return | Not supported | Not listed |
| M104 | Probe arm extend | User M-code range | Not supported | Set hotend temp. |
| M109 | Interactive input | User M-code range | Not supported | Wait for hotend temp. |
Where the controls differ
- M6 tool change. Haas: M06 stops the spindle and coolant (including through-spindle coolant), moves Z to the tool-change position and orients the spindle by itself, so the program does not need M05, M09 or M19 first. LinuxCNC: the spindle stops, but "coolant will continue to flow during the tool change unless it has been turned off by an M9", and M6 does not change the tool length offset, so follow it with G43. With
hal_manualtoolchangeloaded, LinuxCNC stops and prompts the operator. Grbl rejects M6 with error:20. Marlin selects tools and extruders with T0–T7. - M8 / M9 coolant. On LinuxCNC and Grbl, M7 and M8 can both be on and M9 turns both off. On a Haas mill M07 is the optional shower coolant; M09 stops shower and standard coolant; and with the Variable Flow Coolant option, M08 P0 / P1 / P2 run the pump at 50 / 60 / 80 Hz (low, normal, high pressure). Through-spindle coolant is M88 / M89 on Haas mills.
- M30 vs M2. Haas M30 stops the program, spindle and coolant (including TSC) and returns the cursor to the start; since Haas software 100.16.000.1041 it no longer cancels tool length offsets. LinuxCNC M2 and M30 both switch to MDI and reset work offset (G54), plane (G17), distance (G90), feed mode (G94), overrides (M48), cutter comp (G40), spindle (M5), motion (G1) and coolant (M9); M30 also exchanges pallet shuttles, and lines after either are not run. Grbl M2 and M30 reset G1, G17, G90, G94, G54, M5 and M9 but keep F, S and T. Marlin M30 deletes a named file from the SD card.
- M1 optional stop. Grbl accepts M1 and ignores it (its source says "Optional stop not supported"). Marlin documents M1 as a deprecated alias of M0, and both are ignored without an LCD or the emergency parser.
- M19 orient. Haas: P is whole degrees 0–360, R allows two decimals (M19 R123.45); a negative value orients to 0°. LinuxCNC:
M19 R- Q- [P-], where R is the angle 0–360°, Q the seconds to wait for orientation, and P the direction (0 shortest, 1 clockwise, 2 counter-clockwise); it needs a spindle encoder. - One M-code per line. Haas allows one M-code per block and runs it at the end of the block. LinuxCNC allows up to four M words per line from different modal groups, and runs them in a fixed order (M6 before M3, before M7–M9, before the stop codes M0/M1/M2/M30/M60), not in the order written.
- Codes above M99. LinuxCNC reserves M100–M199 for user-defined commands (scripts). Haas uses numbers above 100 for options (M104/M105 probe arm, M130 media display, M138/M139 spindle speed variation). Marlin uses them for printer functions (M104 hotend, M106 fan, M140 bed, M500 save settings). The same number can therefore do very different things.
Haas mill M-codes (full list)
| Code | Haas mill function |
|---|---|
| M00 | Stop program |
| M01 | Optional program stop |
| M02 | Program end |
| M03 | Spindle forward |
| M04 | Spindle reverse |
| M05 | Spindle stop |
| M06 | Tool change |
| M07 | Shower coolant on |
| M08 / M09 | Coolant on / off (M08 Pn sets pump speed with the variable-flow option) |
| M10 / M11 | Engage / release 4th-axis brake |
| M12 / M13 | Engage / release 5th-axis brake |
| M16 | Tool change |
| M19 | Orient spindle (optional P and R values) |
| M21–M25 | Optional user M function with M-Fin |
| M29 | Set output relay with M-Fin |
| M30 | Program end and reset |
| M31 | Chip conveyor forward |
| M33 | Chip conveyor stop |
| M34 | Coolant increment |
| M35 | Coolant decrement |
| M36 | Pallet part ready |
| M39 | Rotate tool turret |
| M41 / M42 | Low / high gear override |
| M46 | Qn Pmm jump to line |
| M48 | Validate that the current program is appropriate for the loaded pallet |
| M50 | Pallet change sequence |
| M51–M55 | Set optional user M-codes |
| M59 | Set output relay |
| M61–M65 | Clear optional user M-codes |
| M69 | Clear output relay |
| M70 / M71 | Workholding clamp / unclamp |
| M73 / M74 | Tool air blast (TAB) on / off |
| M75 | Set G35 or G136 reference point |
| M78 | Alarm if skip signal found |
| M79 | Alarm if skip signal not found |
| M80 / M81 | Auto door open / close |
| M82 | Tool unclamp |
| M83 / M84 | Auto air gun on / off |
| M86 | Tool clamp |
| M88 / M89 | Through-spindle coolant on / off |
| M90 / M91 | Fixture clamp input on / off |
| M95 | Sleep mode |
| M96 | Jump if no input |
| M97 | Local subprogram call (P = N line number, L = 1–99 repeats) |
| M98 | Subprogram call (P = program number, L = 1–99 repeats) |
| M99 | Subprogram return or loop |
| M104 / M105 | Probe arm extend / retract |
| M109 | Interactive user input |
| M116 / M117 | Vise air chip blast on / off |
| M130 / M131 | Display media / cancel display media |
| M138 / M139 | Spindle speed variation on / off |
| M158 / M159 | Mist condenser on / off |
| M160 | Cancel active PulseJet |
| M161 | PulseJet continuous mode |
| M162 | PulseJet single-event mode |
| M163 | PulseJet modal mode |
| M180 / M181 | Auto window open / close |
| M199 | Pallet / part load or program end |
| M300 | APL / robot custom sequence |
Haas lathe M-codes (full list)
| Code | Haas lathe function |
|---|---|
| M00 | Stop program |
| M01 | Optional stop program |
| M02 | Program end |
| M03 | Spindle on forward |
| M04 | Spindle on reverse |
| M05 | Spindle stop |
| M08 / M09 | Coolant on / off |
| M10 / M11 | Chuck clamp / unclamp |
| M12 / M13 | Auto jet air blast on / off (optional) |
| M14 / M15 | Main spindle brake on / off (optional C axis) |
| M17 | Turret rotation forward |
| M18 | Turret rotation reverse |
| M19 | Orient spindle (optional) |
| M21 | Tailstock advance (optional) |
| M22 | Tailstock retract (optional) |
| M23 | Chamfer out of thread on |
| M24 | Chamfer out of thread off |
| M30 | End of program and reset |
| M31 | Chip auger forward (optional) |
| M33 | Chip auger stop (optional) |
| M35 | Parts catcher part-off position |
| M36 | Parts catcher on (optional) |
| M37 | Parts catcher off (optional) |
| M38 / M39 | Spindle speed variation on / off |
| M41 / M42 | Low / high gear (optional) |
| M43 | Turret unlock (service use only) |
| M44 | Turret lock (service use only) |
| M51–M56 | Turn on built-in M-code relay |
| M59 | Turn on output relay |
| M61–M66 | Turn off built-in M-code relay |
| M69 | Turn off output relay |
| M78 | Alarm if skip signal found |
| M79 | Alarm if skip signal not found |
| M85 / M86 | Automatic door open / close (optional) |
| M88 / M89 | High-pressure coolant on / off (optional) |
| M90 / M91 | Fixture clamp input on / off |
| M95 | Sleep mode |
| M96 | Jump if no signal |
| M97 | Local subprogram call |
| M98 | Subprogram call |
| M99 | Subprogram return or loop |
| M104 / M105 | Probe arm extend / retract (optional) |
| M109 | Interactive user input |
| M110 | Secondary spindle chuck clamp (optional) |
| M111 | Secondary spindle chuck unclamp (optional) |
| M112 / M113 | Secondary spindle air blast on / off (optional) |
| M114 / M115 | Secondary spindle brake on / off (optional) |
| M119 | Secondary spindle orient (optional) |
| M121–M126 | Built-in M-code relays with M-Fin |
| M129 | Turn on M-code relay with M-Fin |
| M130 / M131 | Display media / cancel display media |
| M133 | Live tool forward (optional) |
| M134 | Live tool reverse (optional) |
| M135 | Live tool stop (optional) |
| M138 | Spindle speed variation on |
| M139 | Spindle speed variation off |
| M143 | Secondary spindle forward (optional) |
| M144 | Secondary spindle reverse (optional) |
| M145 | Secondary spindle stop (optional) |
| M146 / M147 | Steady rest clamp / unclamp (optional) |
| M158 / M159 | Mist condenser on / off |
| M170 / M171 | Engage / release 4th-axis brake |
| M214 / M215 | Live tool brake on / off |
| M219 | Live tool orient (optional) |
| M299 | APL / part load / or program end |
| M300 | APL / robot custom sequence |
| M334 / M335 | P-Cool increment / decrement |
| M373 / M374 | Tool air blast (TAB) on / off |
| M388 / M389 | Through-spindle coolant on / off |
Mill vs lathe on the same make
- The Haas lathe list has no M06 and no M07; M10 / M11 are the chuck on a lathe but the 4th-axis brake on a mill; M12 / M13 are an air blast on a lathe but the 5th-axis brake on a mill; through-spindle coolant is M88 / M89 on a mill but M388 / M389 on a lathe, where M88 / M89 are high-pressure coolant.
- Spindle speed variation is M138 / M139 on both, and the lathe also lists M38 / M39 for it.
LinuxCNC M-codes
| Code | Function | Modal group |
|---|---|---|
| M0, M1 | Program pause; M1 only with the optional-stop switch on | 4 (stopping) |
| M2, M30 | Program end; M30 also exchanges pallet shuttles | 4 (stopping) |
| M60 | Pallet change pause | 4 (stopping) |
| M3, M4, M5 | Spindle CW, CCW, stop; $n picks the spindle, $-1 all spindles | 7 (spindle) |
| M6 | Tool change to the last T word | 6 (tool change) |
| M7, M8, M9 | Mist on, flood on (both may be on), both off | 8 (coolant) |
| M19 | Orient spindle (R angle, Q timeout s, P direction) | 7 (spindle) |
| M48, M49 | Enable / disable feed and spindle overrides | 9 (overrides) |
| M50 | Feed override control (P1 on, P0 off) | — |
| M51 | Spindle speed override control | — |
| M52 | Adaptive feed control | — |
| M53 | Feed stop control | — |
| M61 | Set current tool number without a tool change (Q) | — |
| M62–M65 | Digital output on/off, synchronised with motion (M62/M63) or immediate (M64/M65) | 5 (I/O) |
| M66 | Wait on a digital or analog input | 5 (I/O) |
| M67, M68 | Analog output, synchronised / immediate | 5 (I/O) |
| M70–M73 | Save, invalidate, restore and auto-restore the modal state | — |
| M98, M99 | Fanuc-style subprogram call and return | — |
| M100–M199 | User-defined M-codes | 10 (user defined) |
Grbl 1.1 M-codes
| Code | Grbl behaviour |
|---|---|
| M0 | Program pause, using a feed hold; resume with ~ (cycle start). |
| M1 | Accepted and ignored. |
| M2, M30 | Program end: resets motion G1, plane G17, distance G90, feed mode G94, work offset G54, spindle M5 and coolant M9. |
| M3, M4, M5 | Spindle CW, CCW, stop; S sets the PWM output between $31 and $30 rpm. With laser mode ($32=1) power changes without stopping. |
| M7 | Mist coolant, only when compiled with ENABLE_M7. |
| M8, M9 | Flood coolant on; M9 turns off both M7 and M8. |
| M56 | Parking motion override, only in builds with parking and this option. |
| Anything else | error:20 (unsupported command), including M6, M19, M48/M49 and M98/M99. See the GRBL error codes. |
Marlin (3D printers): the M-codes that clash with CNC
- Marlin uses M-codes mostly for printer functions: M104 / M109 hotend temperature (set / set and wait), M140 / M190 bed temperature, M106 / M107 fan, M82 / M83 absolute / relative extrusion, M84 steppers off, M500 / M501 / M502 / M503 save / load / reset / report settings. The full list with parameters is on the Marlin G-code and M-code reference.
- M3 / M4 / M5 run a spindle or laser only when Marlin is built with spindle/laser support; M7 / M8 / M9 only with COOLANT_CONTROL. Without those build options they are not available.
- M30 is "Delete SD file" and M48 is a Z-probe repeatability test, so CNC programs must not be sent to a printer unchanged.
Program end on each control
(Haas mill, from Haas's own G81 example) G00 G90 Z1. M09 (Rapid retract, coolant off) G53 G49 Z0 M05 (Z home, spindle off) G53 Y0 (Y home) M30 (End program) % (LinuxCNC, from its G80 example) G80 (turn off canned cycle) G0 X0 (rapid move home) M2 (program end) (Grbl) M5 M9 M30
Comments are written in ( ) because ";" ends the block on Haas and other Fanuc-style controls; LinuxCNC accepts both ( ) and ";" comments. Note Haas's one-M-code-per-line rule: M09 and M05 share their lines with G-codes, not with each other. Paste any of these into the simulator (LinuxCNC or Haas dialect) to see each line explained.
Sources
- Haas Automation, Mill Operator's Manual — 18: Mill M-Codes and Lathe Operator's Manual — Lathe M-Codes (haascnc.com/service/online-operator-s-manuals/…), with the Haas code pages for M00, M01, M02, M03–M05, M06, M07, M08/M09, M19, M29, M30, M97, M98 and M99. haascnc.com blocks automated downloads, so the pages were read from Internet Archive copies captured between July 2024 and August 2025 (web.archive.org). Used for: both Haas lists, the one-M-code-per-block rule, M06, M07, M08 P0–P2, M19, M30 and subprogram details.
- LinuxCNC Project, M-Codes and G-code Overview (modal groups, order of execution), linuxcnc.org/docs/html/gcode/m-code.html and …/overview.html, pages last updated 13 September 2026. Used for: the LinuxCNC list, modal groups, M2/M30 reset list, M6, M7–M9, M19, the four-M-words rule.
- gnea/grbl, Grbl 1.1h source (grbl/gcode.c) and README "List of Supported G-Codes in Grbl v1.1" (github.com/gnea/grbl), 2019. Used for: the Grbl list, M1 ignored, M2/M30 reset, M9 behaviour, unsupported M-codes.
- MarlinFirmware, Marlin G-code index (marlinfw.org/docs/gcode, source github.com/MarlinFirmware/MarlinDocumentation, downloaded 6 October 2026): pages for M0–M1, M3, M5, M7–M9, M30, M48, M104, M109. Used for: the Marlin column.
- All sources were read on 6 October 2026. Fanuc's own manuals are not freely published, so "Fanuc-style" behaviour on this page is taken from Haas's documentation only; check your machine builder's manual for other controls.
Frequently asked questions
What is the difference between M02 and M30?
Both end the program. On Haas, M30 also stops the spindle and coolant and returns the cursor to the start of the program, and Haas calls it the most common way to end a program. On LinuxCNC, M2 and M30 both reset the modal state (G54, G17, G90, G94, G40, M5, M9, G1) and M30 also exchanges pallet shuttles. Grbl treats them the same.
What does M06 do?
M06 changes to the tool selected by the T word (M06 T12 loads tool 12). On a Haas mill it also stops the spindle and coolant, moves Z to the change position and orients the spindle. On LinuxCNC coolant keeps flowing unless M9 was given, and the tool length offset is not changed, so program G43 after M6. Grbl has no M6 (error:20).
What are M07, M08 and M09?
M08 turns flood coolant on and M09 turns coolant off. M07 is mist coolant on LinuxCNC, Grbl (a compile option) and Marlin, but shower coolant on a Haas mill. M09 switches off both M07 and M08 on LinuxCNC and Grbl, and on a Haas it stops shower and standard coolant.
Does M30 end the program on a 3D printer?
No. In Marlin, M30 deletes a file from the SD card, and Marlin's G-code index has no M2. Printer jobs normally end with heater, fan and stepper commands such as M104 S0, M140 S0, M107 and M84.
How many M-codes can be on one line?
Haas allows only one M-code per block, and all M-codes take effect at the end of the block. LinuxCNC allows up to four M words on a line, but not two from the same modal group; Grbl also rejects two from the same group (error:21).