בעקבות התבוסה בהתנגשות הראשונה עם חניבעל, החליט הסנאט הרומאי לשלוח את הקונסול השני טיבריוס סמפרוניוס לונגוס שהמתין עם כוחותיו בסיציליה, לעזרת צבאו של סקיפיו בצפון איטליה. סימפרוניוס היה להוט לצאת לקרב בחניבעל, כדי לזכות ביוקרה פוליטית. חניבעל ניצל את להיטותו כדי לגרור אותו למלכודת והביס את הצבא הרומאי המאוחד בקרב טרביה. לאחר מכן הוא העביר את החורף בשקט, ובשנה הבאה (217 לפנה"ס) הציב מארב מתוחכם לקונסול גאיוס פלאמיניוס נפוס, והשמיד את צבאו בקרב טראסימנוס. כ-15,000 חיילים רומאים כולל פלאמיניוס עצמו נהרגו בקרב זה, ומספר דומה נפל בשבי. הקונסול השני גנאיוס סרוויליוס גמינוס שלא ידע על התבוסה שיגר 4,000 פרשים לעזרת עמיתו, חניבעל שיגר כוח פרשים משלו תחת פיקודו של קצין מוכשר בשם מהרבעל, בהתנגשות נשבו כל הפרשים הרומאים. אותה תקופה איבד חניבעל את עינו בשל דלקת שלקה בה כשעבר באזור ביצות סמוך לפירנצה של ימינו.
חניבעל למעשה יכול היה לעלות כעת על רומא, אולם הוא בחר שלא לעשות זאת, כיוון שלא היו עמו מכונות מצור וחייליו נזקקו למנוחה. הקרב ותבוסת הפרשים זעזעו את רומא המזועזעת בלאו הכי, והוחלט למנות דיקטטור בעיר, דבר שנעשה בשעת חירום בלבד. לתפקיד זה נבחר פאביוס מאקסימוס. פאביוס הבין שחייליו המאומנים היטב של חניבעל עולים על החיילים הרומאיים, ולכן החליט להימנע מקרב ישיר עם חניבעל, ובמקום זאת למצות את יתרונותיהם של הרומאים באספקה בלתי מוגבלת וכוח אדם גדול, וכך להתיש את צבאו של חניבעל בהדרגה. תוכניתו כונתה על שמו "האסטרטגיה הפביאנית", אולם לא הייתה פופולרית בקרב האזרחים ברומא שראו בה תבוסתנות ופחדנות. חניבעל השכיל לנצל רגש זה, והורה לא לפגוע בנכסיו של פאביוס. לשווא ניסה חניבעל לגרות את פאביוס לקרב. עם זאת, באותה שנה (217 לפנה"ס) הזדמן בפני פאביוס פיתוי שלא היה יכול לעמוד בפניו: חניבעל וצבאו תעו בדרכם ונלכדו במעבר צר בין ההרים. פאביוס מיהר וחסם את היציאות וקיווה שחסם את חניבעל. כאן הוכיח חניבעל כושר צבאי ויצירתי ביותר, הוא הורה לקשור לפידים בוערים לקרניהם של שוורים, ולשחרר אותם. הרומאים שבחשכת הלילה סברו שאלו חייליו של חניבעל מיהרו ללכוד אותם, ואפשרו לחניבעל לעבור בשלום. המאורע הכפיש את שמו של פאביוס ברומא.
לקראת סוף השנה נקרא פאביוס לרומא והותיר את סגנו מרקוס מינוקיוס רופוס כמפקד באזור. מינוקיוס חנה מול חניבעל באזור העיר גרוניום (Geronium), והמתין לשעת כושר. חניבעל מצידו השתלט על גרוניום וקיווה להעביר בה את החורף בשקט. הוא פיזר את חייליו כדי שילקטו תבואה בשדות לקראת החורף, ומינוקיוס ניצל את השעה ותקף במהירות, ואך בקושי הצליח חניבעל לסגת באבדות כבדות אל בין חומות גרוניום. הדבר העלה את קרנו של מינוקיוס ברומא, עד שהוחלט למנות אותו ל-"דיקטטור עמית" שווה זכויות לפאביוס, מה שלא נעשה מעולם ברומא. השניים חילקו את הצבא ביניהם ונערכו מול חניבעל בשני מחנות. חניבעל תחקר את שבוייו ולמד להכיר את אופיו של מינוקיוס. הוא הבין שמינוקיוס להוט ביותר להוכיח שהוא טוב יותר מעמיתו, והחליט לנצל להיטות זו. בין המחנה של חניבעל לזה של מינוקיוס הפרידה תלולית שהיוותה עמדה אסטרטגית חשובה, חניבעל תכנן לתפוס אותה אולם ידע שמינוקיוס ינסה למנוע ממנו לעשות זאת, על כן החביא רבים מחייליו באזור ושלח אחרים כביכול לכבוש את התלולית. מינוקיוס שראה זאת מיהר לתקוף, אך אז חייליו של חניבעל זינקו עליו מן המארב. חייליו של מינוקיוס פנו לסגת אך פרשיו של חניבעל טבחו בהם ללא רחם. פאביוס השקיף כל העת על הנעשה בדאגה ולבסוף הורה לחייליו להצטרף למערכה. בלית ברירה הורה חניבעל לחייליו לסגת, וצבאו של מינוקיוס שרד. הוא חזר אל המחנה וגם הרומאים עשו כמוהו. הוא העביר את החורף בגרוניום בבטחה.
קרב קאנאי ותוצאותיו.
עם הגיע האביב של שנת 216 לפנה"ס התפטרו פאביוס ומינוקיוס ממשרותיהם, וכקונסולים של אותה שנה נבחרו לוקיוס אמיליוס פאולוס וגאיוס טרנטיוס וארו. גנאיוס סרוויליוס ומרקוס רגולוס התמנו לפרו קונסולים, וההוראה שקיבלו הייתה להתגרות במחנה חניבעל אך לא לתקוף אותו. חניבעל מצידו עזב את גרוניום וכבש את טירת קאנאי שהייתה נקודה אסטרטגית נוחה, והוא מצא בה גם אספקה בשפע. הסנאט החליט לחדול מהמדיניות של פאביוס ולעבור להתקפה מוחצת שתשמיד כליל את חניבעל. על פי תיאורי ההיסטוריונים העתיקים וארו היה הלהוט לכך ביותר. לצורך כך גייסה רומא צבא אדיר בהיקף חסר תקדים. על פי פוליביוס היו בו 8 לגיונות ועוד 8 לגיונות של בעלי הברית, סה"כ 80,000 ו-6,000 פרשים, ואילו לפי ליוויוס היו בו 4 לגיונות ועוד 4 של בעלי הברית היינו 49,000 איש ו-6,000 פרשים. מרבית החוקרים מאמצים את דעתו של פוליביוס. לחניבעל היו באותה שעה כ-40,000 רגליים ו-10,000 פרשים, שכן צבאו תפח הודות לגאלים שהצטרפו אליו.
הקרב נערך ככל הנראה באזור הנהר אופידוס (בשמו המודרני: אופנטו) ב-2 באוגוסט 216 לפנה"ס. פוליביוס וליוויוס טוענים שווארו חסר הניסיון פיקד באותו יום על הצבא, אולם ככל הנראה ממילא ההוראה לצאת לקרב הגיעה מהסנאט. הקרב נפתח בהסתערות הפרשים הקרתגים באגפים, עליהם פיקדו עזרובעל ומהרבעל, ואלו הביסו במהרה את הפרשים הרומאים. במקביל החלו הרומאים לתקוף את חיל הרגלים הקרתגי שהיה ערוך בצורת חצי סהר שקודקודו כלפי הצבא הרומאי. יתרונם המספרי של הרומאים ואיכות כלי נשקם גרמו לנסיגה הדרגתית של חיילי חניבעל, וכיוון הסהר התהפך. כעת פתחו הקרתגים במטח כידונים, שבעקבותיו הסתערו חיילים לובים חמושים היטב מהאגפים. אנדרלמוסיה פרצה במחנה הרומאי וחיילים ניסו לסגת, אולם אז הגיעו פרשיו של עזרובעל מהעורף, ומה שהתרחש בהמשך דמה יותר לטבח מאשר לקרב. חיילים רומאים רמסו זה את זה כשהקלעים הקרתגים טובחים בהם לבלי רחם.
הניצחון הקרתגי היה שלם. בין 50 אלף ל-70 אלף רומאים נהרגו בקרב, ביניהם הקונסול השני פאולוס, וכמה מאויביו המושבעים של חניבעל, מינוקיוס הדיקטטור לשעבר וגנאיוס סרוויליוס. נוסף להם איבדו הרומאים 80 סנטורים ו-29 טריבונים צבאיים. היה זה אחד הקרבות המתוחכמים ביותר בהיסטוריה הצבאית שהוסיף הילה לשמו של חניבעל.
לאחר הקרב, מהרבעל הציע לעלות על רומא ולכבוש אותה, אולם חניבעל סרב. מהרבעל הזועם הטיח בו "אכן, אין האלים נותנים הכל לאיש אחד. יודע אתה, חניבעל, כיצד לנצח, אך אי אתה יודע כיצד לכלכל את ניצחונך". לא ברור מדוע חניבעל סירב לתקוף את רומא כאשר צבאה הושמד כמעט כליל והעיר נותרה חסרת הגנה כמעט. ג'ון שין (John Shean) מעריך שמחסור בציוד, מכונות מצור ואספקה אילצו את חניבעל לעשות זאת, בעוד הנס דלבריק טען שהמחסור בכוח אדם וההכרח של חניבעל להותיר משמרות בנקודות שונות הם אלו שמנעו זאת ממנו. לדעת אדריאן גולדסוורת'י העובדה שחניבעל סירב לתקוף את רומא מעידה שהוא לא תכנן להרוס אותה, אלא לחתום עמה על הסכם שלום בתנאים נוחים. חוקרים אחרים מבקרים את חניבעל, וסוברים שלמרות כל זאת, מכיוון שפאניקה שררה בכל מקום וכן העובדה ששרשרת הפיקוד הרומאית השתבשה לחלוטין, היה לחניבעל סיכוי לכבוש את העיר בהתקפה מהירה.
חניבעל שלח את אחד מקציניו קרתאלו לרומא, בניסיון להגיע למשא ומתן על הסכם שלום, אולם הסנאט סירב אפילו לדון על אפשרות כזו, וסירב אף לפדות את שבויי קאנאי. המערכה באיטליה המשיכה.
המשך הקרבות באיטליה.
הניצחון בקאנאי היה שיא הקריירה של חניבעל. ערים, כפרים ושבטים רבים הגיעו אליו והציעו את ידידותם. רבות מהערים באיטליה היו למעשה ערים יווניות, גאליות, אטרוסקיות או בנות עמים אחרים, שהיו קשורות בברית עם רומא, והתחייבו לספק לה מיסים וחיילים. הברית שחניבעל הציע הייתה מחייבת הרבה פחות, ולכן רבות מערים אלו העדיפו אותה על פני הברית עם הרומאים. ההצטרפות אל חניבעל שנראה כמנצח הייתה דבר בעתו. עבור חניבעל הבריתות היו חשובות, משום שהן שימשו לו מקלט ומקור אספקה וכן גרעו מכוח האדם הרומי. ערי הנמל שבהן אפשרו לו גישה לים וקשר רציף עם קרתגו, ושללו מן הצי הרומי בסיסים ימיים חשובים. מנגד, רבים מההיסטוריונים מחזיקים בדעה שהערים היו יותר מכשול מאשר סיוע, משום שהן הכריחו את חניבעל לצאת ולהגן עליהן בכל פעם שהרומאים תקפו אותן. לטענת ליוויוס, שפע המותרות שהציעו כעת עריה העשירות של דרום איטליה פגעו בחוסנו המקורי של הצבא הקרתגי.
לאחר הניצחון בקאנאי צעד חניבעל מזרחה לאורך החוף האדריאטי, ושלח את אחיו מאגו לקרתגו במטרה לבקש תגבורת. מאגו שפך בפני מועצת הזקנים 6,000 טבעות של אצילים רומאים וביקש סיוע, אולם חנו הגדול, מתנגדם הפוליטי של בני ברקה, התקיף אותו בתגובה בסדרת שאלות שהביכו אותו. למרות זאת גויס צבא גדול שהיה אמור להישלח אל איטליה עם מאגו, אולם לאחר התבוסה בקרב דרטוסה נשלח מאגו להיספניה כדי לסייע לאחיו השני עזרובעל במערכה נגד הרומאים שם. יש המעריכים שמטרת המועצה הייתה למעשה גדולה יותר, וכוונתה הייתה למגר את האחים הסקיפיונים בהיספניה ולאחר מכן לפתוח את הגישה לאיטליה דרך גאליה והאלפים, כפי שעשה חניבעל. תוכנית זו נבעה ככל הנראה מעליונותו של הצי הרומי, דבר שסיכן כל אפשרות לשינוע תגבורות בים.